Subversion Repositories HomeAutomation

Rev

Rev 1620 | Rev 1647 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 1620 Rev 1642
1
/*
1
/*
2
 *
2
 *
3
 *  Copyright (C) 2010  Mattias Runge
3
 *  Copyright (C) 2010  Mattias Runge
4
 *
4
 *
5
 *  This program is free software; you can redistribute it and/or modify
5
 *  This program is free software; you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation; either version 2 of the License, or
7
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  (at your option) any later version.
8
 *  (at your option) any later version.
9
 *
9
 *
10
 *  This program is distributed in the hope that it will be useful,
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
13
 *  GNU General Public License for more details.
14
 *
14
 *
15
 *  You should have received a copy of the GNU General Public License along
15
 *  You should have received a copy of the GNU General Public License along
16
 *  with this program; if not, write to the Free Software Foundation, Inc.,
16
 *  with this program; if not, write to the Free Software Foundation, Inc.,
17
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
 *
18
 *
19
 */
19
 */
20
 
20
 
21
#include <string>
21
#include <string>
22
#include <vector>
22
#include <vector>
23
 
23
 
24
#include <signal.h>
24
#include <signal.h>
25
#include <stdio.h>
25
#include <stdio.h>
26
#include <stdlib.h>
26
#include <stdlib.h>
27
#include <pwd.h>
27
#include <pwd.h>
28
 
28
 
29
#include <boost/lexical_cast.hpp>
29
#include <boost/lexical_cast.hpp>
30
#include <boost/thread/mutex.hpp>
30
#include <boost/thread/mutex.hpp>
31
#include <boost/thread/condition.hpp>
31
#include <boost/thread/condition.hpp>
32
#include <boost/thread/locks.hpp>
32
#include <boost/thread/locks.hpp>
33
#include <boost/algorithm/string.hpp>
33
#include <boost/algorithm/string.hpp>
34
 
34
 
35
#include "net/Manager.h"
35
#include "net/Manager.h"
36
#include "net/Subscriber.h"
36
#include "net/Subscriber.h"
37
#include "net/types.h"
37
#include "net/types.h"
38
 
38
 
39
#include "type/common.h"
39
#include "common/common.h"
40
 
40
 
41
#include <readline/readline.h>
41
#include <readline/readline.h>
42
#include <readline/history.h>
42
#include <readline/history.h>
43
 
43
 
44
using namespace atom;
44
using namespace atom;
45
 
45
 
46
 
46
 
47
void Handler(int status);
47
void Handler(int status);
48
void CleanUp();
48
void CleanUp();
49
 
49
 
50
char* AutoCompleteGet(const char* text, int state);
50
char* AutoCompleteGet(const char* text, int state);
51
static char** AutoComplete(const char* text, int start, int end);
51
static char** AutoComplete(const char* text, int start, int end);
52
 
52
 
53
type::StringList autocomplete_list;
53
common::StringList autocomplete_list;
54
char* buffer = NULL;
54
char* buffer = NULL;
55
bool waiting_for_autocomplete = false;
55
bool waiting_for_autocomplete = false;
56
boost::condition on_message_condition;
56
boost::condition on_message_condition;
57
boost::mutex guard_mutex;
57
boost::mutex guard_mutex;
58
std::string prompt;
58
std::string prompt;
59
int prompt_id = -1;
59
int prompt_id = -1;
60
 
60
 
61
class ConsoleClient : public net::Subscriber
61
class ConsoleClient : public net::Subscriber
62
{
62
{
63
public:
63
public:
64
    typedef boost::shared_ptr<ConsoleClient> Pointer;
64
    typedef boost::shared_ptr<ConsoleClient> Pointer;
65
   
65
   
66
    ConsoleClient(std::string address, unsigned int port)
66
    ConsoleClient(std::string address, unsigned int port)
67
    {
67
    {
68
        this->identifier_ = address + ":" + boost::lexical_cast<std::string>(port);
68
        this->identifier_ = address + ":" + boost::lexical_cast<std::string>(port);
69
        this->client_id_ = net::Manager::Instance()->Connect(net::PROTOCOL_TCP, address, port);
69
        this->client_id_ = net::Manager::Instance()->Connect(net::PROTOCOL_TCP, address, port);
70
    }
70
    }
71
   
71
   
72
    virtual ~ConsoleClient()
72
    virtual ~ConsoleClient()
73
    {
73
    {
74
        net::Manager::Instance()->Disconnect(this->client_id_);
74
        net::Manager::Instance()->Disconnect(this->client_id_);
75
 
75
 
76
        this->io_service_.stop();
76
        this->io_service_.stop();
77
    }
77
    }
78
   
78
   
79
    void Send(std::string data)
79
    void Send(std::string data)
80
    {
80
    {
81
        net::Manager::Instance()->SendTo(this->client_id_, data);
81
        net::Manager::Instance()->SendTo(this->client_id_, data);
82
    }
82
    }
83
   
83
   
84
    bool IsConnected()
84
    bool IsConnected()
85
    {
85
    {
86
        return this->client_id_ != 0;
86
        return this->client_id_ != 0;
87
    }
87
    }
88
   
88
   
89
    std::string GetIdentifier()
89
    std::string GetIdentifier()
90
    {
90
    {
91
        return this->identifier_;
91
        return this->identifier_;
92
    }
92
    }
93
   
93
   
94
private:
94
private:
95
    net::ClientId client_id_;
95
    net::ClientId client_id_;
96
    std::string identifier_;
96
    std::string identifier_;
97
   
97
   
98
   
98
   
99
    void SlotOnNewStateHandler(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
99
    void SlotOnNewStateHandler(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
100
    {
100
    {
101
        if (client_state == net::CLIENT_STATE_CONNECTED)
101
        if (client_state == net::CLIENT_STATE_CONNECTED)
102
        {
102
        {
103
            printf("Connected to Atom Daemon!\n");
103
            printf("Connected to Atom Daemon!\n");
104
        }
104
        }
105
        else
105
        else
106
        {
106
        {
107
            printf("\nDisconnected!\n");
107
            printf("\nDisconnected!\n");
108
            this->client_id_ = 0;
108
            this->client_id_ = 0;
109
           
109
           
110
            kill(getpid(), SIGTERM);
110
            kill(getpid(), SIGTERM);
111
        }
111
        }
112
    }
112
    }
113
   
113
   
114
    void SlotOnNewDataHandler(net::ClientId client_id, net::ServerId server_id, type::Byteset data)
114
    void SlotOnNewDataHandler(net::ClientId client_id, net::ServerId server_id, common::Byteset data)
115
    {
115
    {
116
        prompt_id = -1;
116
        prompt_id = -1;
117
       
117
       
118
        std::string s(data.ToCharString());
118
        std::string s(data.ToCharString());
119
       
119
       
120
        if (waiting_for_autocomplete)
120
        if (waiting_for_autocomplete)
121
        {
121
        {
122
            autocomplete_list.clear();
122
            autocomplete_list.clear();
123
           
123
           
124
            boost::algorithm::trim_if(s, boost::is_any_of("\n"));
124
            boost::algorithm::trim_if(s, boost::is_any_of("\n"));
125
            boost::algorithm::trim_if(s, boost::is_any_of(" "));
125
            boost::algorithm::trim_if(s, boost::is_any_of(" "));
126
           
126
           
127
            if (s != "")
127
            if (s != "")
128
            {
128
            {
129
                boost::algorithm::split(autocomplete_list, s, boost::is_any_of("\n"), boost::algorithm::token_compress_on);
129
                boost::algorithm::split(autocomplete_list, s, boost::is_any_of("\n"), boost::algorithm::token_compress_on);
130
            }
130
            }
131
        }
131
        }
132
        else
132
        else
133
        {
133
        {
134
            type::StringList lines;
134
            common::StringList lines;
135
           
135
           
136
            boost::algorithm::split(lines, s, boost::is_any_of("\n"), boost::algorithm::token_compress_on);
136
            boost::algorithm::split(lines, s, boost::is_any_of("\n"), boost::algorithm::token_compress_on);
137
           
137
           
138
            for (unsigned int n = 0; n < lines.size(); n++)
138
            for (unsigned int n = 0; n < lines.size(); n++)
139
            {
139
            {
140
                type::StringList parts;
140
                common::StringList parts;
141
               
141
               
142
                boost::algorithm::split(parts, lines[n], boost::is_any_of(";"), boost::algorithm::token_compress_off);
142
                boost::algorithm::split(parts, lines[n], boost::is_any_of(";"), boost::algorithm::token_compress_off);
143
               
143
               
144
                if (parts[0].length() == 1 && parts[0] == "P")
144
                if (parts[0].length() == 1 && parts[0] == "P")
145
                {
145
                {
146
                    prompt_id = boost::lexical_cast<unsigned int>(parts[1]);
146
                    prompt_id = boost::lexical_cast<unsigned int>(parts[1]);
147
                   
147
                   
148
                    prompt = "";
148
                    prompt = "";
149
                   
149
                   
150
                    for (unsigned int c = 2; c < parts.size(); c++)
150
                    for (unsigned int c = 2; c < parts.size(); c++)
151
                    {
151
                    {
152
                        prompt += parts[c] + " ";
152
                        prompt += parts[c] + " ";
153
                    }
153
                    }
154
                }
154
                }
155
                else
155
                else
156
                {
156
                {
157
                    boost::algorithm::trim_if(lines[n], boost::is_any_of(" "));
157
                    boost::algorithm::trim_if(lines[n], boost::is_any_of(" "));
158
                   
158
                   
159
                    if (lines[n] != "")
159
                    if (lines[n] != "")
160
                    {
160
                    {
161
                        printf("%s\n", lines[n].data());
161
                        printf("%s\n", lines[n].data());
162
                    }
162
                    }
163
                }
163
                }
164
            }
164
            }
165
        }
165
        }
166
         
166
         
167
        on_message_condition.notify_all();
167
        on_message_condition.notify_all();
168
    }
168
    }
169
};
169
};
170
 
170
 
171
ConsoleClient::Pointer cc;
171
ConsoleClient::Pointer cc;
172
struct termios original_flags;
172
struct termios original_flags;
173
std::string history_filename;
173
std::string history_filename;
174
 
174
 
175
int main(int argc, char **argv)
175
int main(int argc, char **argv)
176
{
176
{
177
    signal(SIGTERM, Handler);
177
    signal(SIGTERM, Handler);
178
    signal(SIGINT, Handler);
178
    signal(SIGINT, Handler);
179
    signal(SIGQUIT, Handler);
179
    signal(SIGQUIT, Handler);
180
    signal(SIGABRT, Handler);
180
    signal(SIGABRT, Handler);
181
    signal(SIGPIPE, Handler);
181
    signal(SIGPIPE, Handler);
182
   
182
   
183
    tcgetattr(fileno(stdin), &original_flags);
183
    tcgetattr(fileno(stdin), &original_flags);
184
       
184
       
185
    printf("Atom Interactive Console, version 1.5.0 starting...\n");
185
    printf("Atom Interactive Console, version 1.5.0 starting...\n");
186
    printf("Written by Mattias Runge 2010.\n");
186
    printf("Written by Mattias Runge 2010.\n");
187
    printf("Released under GPL version 2.\n");
187
    printf("Released under GPL version 2.\n");
188
   
188
   
189
    net::Manager::Create();
189
    net::Manager::Create();
190
   
190
   
191
    std::string address = "localhost";
191
    std::string address = "localhost";
192
    unsigned int port = 1202;
192
    unsigned int port = 1202;
193
   
193
   
194
    printf("Connecting to %s:%d...", address.data(), port);
194
    printf("Connecting to %s:%d...", address.data(), port);
195
   
195
   
196
    try
196
    try
197
    {
197
    {
198
        cc = ConsoleClient::Pointer(new ConsoleClient(address, port));
198
        cc = ConsoleClient::Pointer(new ConsoleClient(address, port));
199
    }
199
    }
200
    catch (std::runtime_error& e)
200
    catch (std::runtime_error& e)
201
    {
201
    {
202
        printf("%s\n", e.what());
202
        printf("%s\n", e.what());
203
        CleanUp();
203
        CleanUp();
204
       
204
       
205
        return EXIT_FAILURE;
205
        return EXIT_FAILURE;
206
    }
206
    }
207
   
207
   
208
    printf("success!\n");
208
    printf("success!\n");
209
   
209
   
210
    prompt = cc->GetIdentifier() + "] ";
210
    prompt = cc->GetIdentifier() + "] ";
211
   
211
   
212
    passwd* user_struct = getpwuid(getuid());
212
    passwd* user_struct = getpwuid(getuid());
213
   
213
   
214
    history_filename = std::string(user_struct->pw_dir) + "/.atomic_history";
214
    history_filename = std::string(user_struct->pw_dir) + "/.atomic_history";
215
   
215
   
216
    read_history(history_filename.data());
216
    read_history(history_filename.data());
217
   
217
   
218
    rl_attempted_completion_function = AutoComplete;
218
    rl_attempted_completion_function = AutoComplete;
219
   
219
   
220
    while ((buffer = readline(prompt.data())) != NULL)
220
    while ((buffer = readline(prompt.data())) != NULL)
221
    {
221
    {
222
        if (strlen(buffer) == 0)
222
        if (strlen(buffer) == 0)
223
        {
223
        {
224
            continue;
224
            continue;
225
        }
225
        }
226
       
226
       
227
        if (strcmp(buffer, "quit") == 0)
227
        if (strcmp(buffer, "quit") == 0)
228
        {
228
        {
229
            break;
229
            break;
230
        }
230
        }
231
       
231
       
232
        waiting_for_autocomplete = false;
232
        waiting_for_autocomplete = false;
233
        prompt = cc->GetIdentifier() + "] ";
233
        prompt = cc->GetIdentifier() + "] ";
234
       
234
       
235
        if (prompt_id == -1)
235
        if (prompt_id == -1)
236
        {
236
        {
237
            cc->Send("E;" + std::string(buffer));
237
            cc->Send("E;" + std::string(buffer));
238
            add_history(buffer);
238
            add_history(buffer);
239
        }
239
        }
240
        else
240
        else
241
        {
241
        {
242
            cc->Send("R;" + boost::lexical_cast<std::string>(prompt_id) + ";" + std::string(buffer));
242
            cc->Send("R;" + boost::lexical_cast<std::string>(prompt_id) + ";" + std::string(buffer));
243
            prompt_id = -1;
243
            prompt_id = -1;
244
        }
244
        }
245
       
245
       
246
        boost::mutex::scoped_lock guard(guard_mutex);
246
        boost::mutex::scoped_lock guard(guard_mutex);
247
        on_message_condition.wait(guard);    
247
        on_message_condition.wait(guard);    
248
    }
248
    }
249
   
249
   
250
    CleanUp();
250
    CleanUp();
251
   
251
   
252
    return EXIT_SUCCESS;
252
    return EXIT_SUCCESS;
253
}
253
}
254
 
254
 
255
static char** AutoComplete(const char* text, int start, int end)
255
static char** AutoComplete(const char* text, int start, int end)
256
{
256
{
257
    unsigned int count = 0;
257
    unsigned int count = 0;
258
   
258
   
259
    //printf("\nAutoComplete:start=%d, end=%d\n", start, end);
259
    //printf("\nAutoComplete:start=%d, end=%d\n", start, end);
260
   
260
   
261
    for (unsigned int n = 0; n < start; n++)
261
    for (unsigned int n = 0; n < start; n++)
262
    {
262
    {
263
        if (rl_line_buffer[n] == ' ')
263
        if (rl_line_buffer[n] == ' ')
264
        {
264
        {
265
            count++;
265
            count++;
266
        }
266
        }
267
    }
267
    }
268
   
268
   
269
    waiting_for_autocomplete = true;
269
    waiting_for_autocomplete = true;
270
   
270
   
271
 
271
 
272
    std::string request = "A;"+ boost::lexical_cast<std::string>(count) + ";" + std::string(rl_line_buffer);
272
    std::string request = "A;"+ boost::lexical_cast<std::string>(count) + ";" + std::string(rl_line_buffer);
273
    //printf("\nSending request:%s\n", request.data());
273
    //printf("\nSending request:%s\n", request.data());
274
   
274
   
275
    cc->Send(request);
275
    cc->Send(request);
276
   
276
   
277
    boost::mutex::scoped_lock guard(guard_mutex);
277
    boost::mutex::scoped_lock guard(guard_mutex);
278
    on_message_condition.wait(guard);    
278
    on_message_condition.wait(guard);    
279
   
279
   
280
    if (autocomplete_list.size() == 0)
280
    if (autocomplete_list.size() == 0)
281
    {
281
    {
282
        return NULL;
282
        return NULL;
283
    }
283
    }
284
   
284
   
285
    //printf("processing response\n");
285
    //printf("processing response\n");
286
   
286
   
287
    return rl_completion_matches(text, &AutoCompleteGet);
287
    return rl_completion_matches(text, &AutoCompleteGet);
288
}
288
}
289
 
289
 
290
char* AutoCompleteGet(const char* text, int state)
290
char* AutoCompleteGet(const char* text, int state)
291
{
291
{
292
    static int index = 0;
292
    static int index = 0;
293
    int length = strlen(text);
293
    int length = strlen(text);
294
    std::string name;
294
    std::string name;
295
   
295
   
296
    //printf("run, %s, %d, %d\n", text, state, autocomplete_list.size());
296
    //printf("run, %s, %d, %d\n", text, state, autocomplete_list.size());
297
   
297
   
298
    if (!state) // First run
298
    if (!state) // First run
299
    {
299
    {
300
        index = 0;
300
        index = 0;
301
    }
301
    }
302
   
302
   
303
    while (autocomplete_list.size() > index)
303
    while (autocomplete_list.size() > index)
304
    {
304
    {
305
        name = autocomplete_list[index];
305
        name = autocomplete_list[index];
306
        //printf("testing name = %s\n", name.data());
306
        //printf("testing name = %s\n", name.data());
307
       
307
       
308
        index++;
308
        index++;
309
       
309
       
310
        if (strncmp(name.data(), text, length) == 0)
310
        if (strncmp(name.data(), text, length) == 0)
311
        {
311
        {
312
            char *result = (char*)malloc(name.size() + 1);
312
            char *result = (char*)malloc(name.size() + 1);
313
            strcpy(result, name.data());
313
            strcpy(result, name.data());
314
           
314
           
315
            return result;
315
            return result;
316
        }
316
        }
317
    }
317
    }
318
   
318
   
319
    return NULL;
319
    return NULL;
320
}
320
}
321
 
321
 
322
void CleanUp()
322
void CleanUp()
323
{
323
{
324
    printf("Cleaning up...\n");
324
    printf("Cleaning up...\n");
325
 
325
 
326
    write_history(history_filename.data());
326
    write_history(history_filename.data());
327
   
327
   
328
    cc.reset();
328
    cc.reset();
329
   
329
   
330
    net::Manager::Delete();
330
    net::Manager::Delete();
331
   
331
   
332
    if (buffer != NULL)
332
    if (buffer != NULL)
333
    {
333
    {
334
        free(buffer);
334
        free(buffer);
335
    }
335
    }
336
   
336
   
337
    printf("Thank you for using Atom. Goodbye!\n");
337
    printf("Thank you for using Atom. Goodbye!\n");
338
   
338
   
339
    tcsetattr(fileno(stdin), TCSANOW, &original_flags); // Restore
339
    tcsetattr(fileno(stdin), TCSANOW, &original_flags); // Restore
340
}
340
}
341
 
341
 
342
void Handler(int status)
342
void Handler(int status)
343
{
343
{
344
    std::string signal_name = "Unknown";
344
    std::string signal_name = "Unknown";
345
   
345
   
346
    switch (status)
346
    switch (status)
347
    {
347
    {
348
        case SIGTERM:
348
        case SIGTERM:
349
        {
349
        {
350
            signal_name = "Terminate";
350
            signal_name = "Terminate";
351
            break;
351
            break;
352
        }  
352
        }  
353
        case SIGINT:
353
        case SIGINT:
354
        {
354
        {
355
            signal_name = "Interupt";
355
            signal_name = "Interupt";
356
            break;
356
            break;
357
        }  
357
        }  
358
        case SIGQUIT:
358
        case SIGQUIT:
359
        {
359
        {
360
            signal_name = "Quit";
360
            signal_name = "Quit";
361
            break;
361
            break;
362
        }  
362
        }  
363
        case SIGABRT:
363
        case SIGABRT:
364
        {
364
        {
365
            signal_name = "Abort";
365
            signal_name = "Abort";
366
            break;
366
            break;
367
        }  
367
        }  
368
        case SIGIO:
368
        case SIGIO:
369
        {
369
        {
370
            signal_name = "I/O";
370
            signal_name = "I/O";
371
            break;
371
            break;
372
        }  
372
        }  
373
        case SIGPIPE:
373
        case SIGPIPE:
374
        {
374
        {
375
            signal_name = "Pipe";
375
            signal_name = "Pipe";
376
            break;
376
            break;
377
        }
377
        }
378
    }
378
    }
379
   
379
   
380
   
380
   
381
    if (status != SIGPIPE)
381
    if (status != SIGPIPE)
382
    {
382
    {
383
        CleanUp();
383
        CleanUp();
384
        exit(0);
384
        exit(0);
385
        //on_message_condition.notify_all();
385
        //on_message_condition.notify_all();
386
    }
386
    }
387
}
387
}