Subversion Repositories HomeAutomation

Rev

Rev 1608 | Rev 1620 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

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