1/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10** GNU General Public License for more details.
11*/
12#include "remote_call.h"
13#include "android/utils/bufprint.h"
14#include "android/utils/debug.h"
15#include "sysdeps.h"
16#include "gsm.h"
17#include "android/android.h"
18#include "sockets.h"
19#include <stdlib.h>
20
21#define  DEBUG  1
22
23#if 1
24#  define  D_ACTIVE  VERBOSE_CHECK(modem)
25#else
26#  define  D_ACTIVE  DEBUG
27#endif
28
29#if 1
30#  define  S_ACTIVE  VERBOSE_CHECK(socket)
31#else
32#  define  S_ACTIVE  DEBUG
33#endif
34
35#if DEBUG
36#  include <stdio.h>
37#  define  D(...)   do { if (D_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0)
38#  define  S(...)   do { if (S_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0)
39#else
40#  define  D(...)   ((void)0)
41#  define  S(...)   ((void)0)
42#endif
43
44/** By convention, remote numbers are the console ports, i.e. 5554, 5556, etc...
45 **/
46#define  REMOTE_NUMBER_BASE       5554
47#define  REMOTE_NUMBER_MAX        16
48#define  REMOTE_NUMBER_MAX_CHARS  4
49#define  REMOTE_CONSOLE_PORT      5554
50
51int
52remote_number_from_port( int  port )
53{
54    if (port & 1)  /* must be even */
55        return -1;
56
57    port = (port - REMOTE_CONSOLE_PORT) >> 1;
58    if ((unsigned)port >= REMOTE_NUMBER_MAX)
59        return -1;
60
61    return REMOTE_NUMBER_BASE + port*2;
62}
63
64int
65remote_number_to_port( int  number )
66{
67    if (number & 1)  /* must be even */
68        return -1;
69
70    number = (number - REMOTE_NUMBER_BASE) >> 1;
71    if ((unsigned)number >= REMOTE_NUMBER_MAX)
72        return -1;
73
74    return REMOTE_CONSOLE_PORT + number*2;
75}
76
77int
78remote_number_string_to_port( const char*  number )
79{
80    char*  end;
81    long   num;
82    const char*  temp = number;
83    int    len;
84
85    len = strlen(number);
86    if (len > 0 && number[len-1] == ';')
87        len--;
88    if (len == 11 && !memcmp(number, PHONE_PREFIX, 7))
89        temp += 7;
90    num = strtol( temp, &end, 10 );
91
92    if (end == NULL || *end || (int)num != num )
93        return -1;
94
95    return remote_number_to_port( (int)num );
96}
97
98/** REMOTE CALL OBJECTS
99 **/
100
101typedef struct RemoteCallRec {
102    struct RemoteCallRec*   next;
103    struct RemoteCallRec**  pref;
104    RemoteCallType          type;
105    int                     to_port;
106    int                     from_port;
107    SysChannel              channel;
108    RemoteResultFunc        result_func;
109    void*                   result_opaque;
110
111    char                    quitting;
112
113    /* the output buffer */
114    char*                   buff;
115    int                     buff_pos;
116    int                     buff_len;
117    int                     buff_size;
118    char                    buff0[32];
119
120} RemoteCallRec, *RemoteCall;
121
122static void
123remote_call_done( RemoteCall  call )
124{
125    call->pref[0] = call->next;
126    call->next    = NULL;
127    call->pref    = &call->next;
128
129    if (call->buff && call->buff != call->buff0) {
130        free(call->buff);
131        call->buff      = call->buff0;
132        call->buff_size = (int) sizeof(call->buff0);
133    }
134
135    if ( call->channel ) {
136        sys_channel_close( call->channel );
137        call->channel = NULL;
138    }
139
140    call->buff_pos = 0;
141    call->buff_len = 0;
142}
143
144
145static void
146remote_call_free( RemoteCall  call )
147{
148    if (call) {
149        remote_call_done( call );
150        free(call);
151    }
152}
153
154
155static void  remote_call_event( void*  opaque, int  events );  /* forward */
156
157static RemoteCall
158remote_call_alloc( RemoteCallType  type, int  to_port, int  from_port )
159{
160    RemoteCall  rcall    = calloc( sizeof(*rcall), 1 );
161    int         from_num = remote_number_from_port(from_port);
162
163    if (rcall != NULL) {
164        char  *p, *end;
165
166        rcall->pref      = &rcall->next;
167        rcall->type      = type;
168        rcall->to_port   = to_port;
169        rcall->from_port = from_port;
170        rcall->buff      = rcall->buff0;
171        rcall->buff_size = sizeof(rcall->buff0);
172        rcall->buff_pos  = 0;
173
174        p   = rcall->buff;
175        end = p + rcall->buff_size;
176
177        switch (type) {
178            case REMOTE_CALL_DIAL:
179                p = bufprint(p, end, "gsm call " PHONE_PREFIX "%d\n", from_num );
180                break;
181
182            case REMOTE_CALL_BUSY:
183                p = bufprint(p, end, "gsm busy " PHONE_PREFIX "%d\n", from_num);
184                break;
185
186            case REMOTE_CALL_HOLD:
187                p = bufprint(p, end, "gsm hold " PHONE_PREFIX "%d\n", from_num);
188                break;
189
190            case REMOTE_CALL_ACCEPT:
191                p = bufprint(p, end, "gsm accept " PHONE_PREFIX "%d\n", from_num);
192                break;
193
194            case REMOTE_CALL_HANGUP:
195                p = bufprint(p, end, "gsm cancel " PHONE_PREFIX "%d\n", from_num );
196                break;
197
198            default:
199                ;
200        }
201        if (p >= end) {
202            D("%s: buffer too short\n", __FUNCTION__ );
203            remote_call_free(rcall);
204            return NULL;
205        }
206
207        rcall->buff_len = p - rcall->buff;
208
209        rcall->channel = sys_channel_create_tcp_client( "localhost", to_port );
210        if (rcall->channel == NULL) {
211            D("%s: could not create channel to port %d\n", __FUNCTION__, to_port);
212            remote_call_free(rcall);
213            return NULL;
214        }
215
216        sys_channel_on( rcall->channel, SYS_EVENT_WRITE, remote_call_event, rcall );
217    }
218    return  rcall;
219}
220
221
222static int
223remote_call_set_sms_pdu( RemoteCall  call,
224                         SmsPDU      pdu )
225{
226    char  *p, *end;
227    int    msg2len;
228
229    msg2len = 32 + smspdu_to_hex( pdu, NULL, 0 );
230    if (msg2len > call->buff_size) {
231        char*  old_buff = call->buff == call->buff0 ? NULL : call->buff;
232        char*  new_buff = realloc( old_buff, msg2len );
233        if (new_buff == NULL) {
234            D("%s: not enough memory to alloc %d bytes", __FUNCTION__, msg2len);
235            return -1;
236        }
237        call->buff      = new_buff;
238        call->buff_size = msg2len;
239    }
240
241    p   = call->buff;
242    end = p + call->buff_size;
243
244    p  = bufprint(p, end, "sms pdu ");
245    p += smspdu_to_hex( pdu, p, end-p );
246    *p++ = '\n';
247    *p = 0;
248
249    call->buff_len = p - call->buff;
250    call->buff_pos = 0;
251    return 0;
252}
253
254
255static void
256remote_call_add( RemoteCall   call,
257                 RemoteCall  *plist )
258{
259    RemoteCall  first = *plist;
260
261    call->next = first;
262    call->pref = plist;
263
264    if (first)
265        first->pref = &call->next;
266}
267
268static void
269remote_call_event( void*  opaque, int  events )
270{
271    RemoteCall  call = opaque;
272
273    S("%s: called for call (%d,%d), events=%02x\n", __FUNCTION__,
274       call->from_port, call->to_port, events);
275
276    if (events & SYS_EVENT_READ) {
277        /* simply drain the channel */
278        char  temp[32];
279        int  n = sys_channel_read( call->channel, temp, sizeof(temp) );
280        if (n <= 0) {
281            /* remote emulator probably quitted */
282            //S("%s: emulator %d quitted with %d: %s\n", __FUNCTION__, call->to_port, errno, errno_str);
283            remote_call_free( call );
284            return;
285        }
286    }
287
288    if (events & SYS_EVENT_WRITE) {
289        int  n;
290
291        if (S_ACTIVE) {
292            int  nn;
293            S("%s: call (%d,%d) sending %d bytes '", __FUNCTION__,
294            call->from_port, call->to_port, call->buff_len - call->buff_pos );
295            for (nn = call->buff_pos; nn < call->buff_len; nn++) {
296                int  c = call->buff[nn];
297                if (c < 32) {
298                    if (c == '\n')
299                        S("\\n");
300                    else if (c == '\t')
301                        S("\\t");
302                    else if (c == '\r')
303                        S("\\r");
304                    else
305                        S("\\x%02x", c);
306                } else
307                    S("%c", c);
308            }
309            S("'\n");
310        }
311
312        n = sys_channel_write( call->channel,
313                               call->buff + call->buff_pos,
314                               call->buff_len - call->buff_pos );
315        if (n <= 0) {
316            /* remote emulator probably quitted */
317            S("%s: emulator %d quitted unexpectedly with error %d: %s\n",
318                    __FUNCTION__, call->to_port, errno, errno_str);
319            if (call->result_func)
320                call->result_func( call->result_opaque, 0 );
321            remote_call_free( call );
322            return;
323        }
324        call->buff_pos += n;
325
326        if (call->buff_pos >= call->buff_len) {
327            /* cool, we sent everything */
328            S("%s: finished sending data to %d\n", __FUNCTION__, call->to_port);
329            if (!call->quitting) {
330                    call->quitting = 1;
331                    sprintf( call->buff, "quit\n" );
332                    call->buff_len = strlen(call->buff);
333                    call->buff_pos = 0;
334            } else {
335                call->quitting = 0;
336                if (call->result_func)
337                    call->result_func( call->result_opaque, 1 );
338
339                sys_channel_on( call->channel, SYS_EVENT_READ, remote_call_event, call );
340            }
341        }
342    }
343}
344
345static RemoteCall  _the_remote_calls;
346
347#if 0
348static int
349remote_from_number( const char*  from )
350{
351    char*  end;
352    long   num = strtol( from, &end, 10 );
353
354    if (end == NULL || *end)
355        return -1;
356
357    if ((unsigned)(num - REMOTE_NUMBER_BASE) >= REMOTE_NUMBER_MAX)
358        return -1;
359
360    return (int) num;
361}
362#endif
363
364static RemoteCall
365remote_call_generic( RemoteCallType  type, const char*  to_number, int  from_port )
366{
367    int         to_port = remote_number_string_to_port(to_number);
368    RemoteCall  call;
369
370    if ( remote_number_from_port(from_port) < 0 ) {
371        D("%s: from_port value %d is not valid", __FUNCTION__, from_port);
372        return NULL;
373    }
374    if ( to_port < 0 ) {
375        D("%s: phone number '%s' is not decimal or remote", __FUNCTION__, to_number);
376        return NULL;
377    }
378    if (to_port == from_port) {
379        D("%s: trying to call self\n", __FUNCTION__);
380        return NULL;
381    }
382    call = remote_call_alloc( type, to_port, from_port );
383    if (call == NULL) {
384        return NULL;
385    }
386    remote_call_add( call, &_the_remote_calls );
387    D("%s: adding new call from port %d to port %d\n", __FUNCTION__, from_port, to_port);
388    return call;
389}
390
391
392int
393remote_call_dial( const char*       number,
394                  int               from,
395                  RemoteResultFunc  result_func,
396                  void*             result_opaque )
397{
398    RemoteCall   call = remote_call_generic( REMOTE_CALL_DIAL, number, from );
399
400    if (call != NULL) {
401        call->result_func   = result_func;
402        call->result_opaque = result_opaque;
403    }
404    return call ? 0 : -1;
405}
406
407
408void
409remote_call_other( const char*  to_number, int  from_port, RemoteCallType  type )
410{
411    remote_call_generic( type, to_number, from_port );
412}
413
414/* call this function to send a SMS to a remote emulator */
415int
416remote_call_sms( const char*   number,
417                 int           from,
418                 SmsPDU        pdu )
419{
420    RemoteCall   call = remote_call_generic( REMOTE_CALL_SMS, number, from );
421
422    if (call == NULL)
423        return -1;
424
425    if (call != NULL) {
426        if ( remote_call_set_sms_pdu( call, pdu ) < 0 ) {
427            remote_call_free(call);
428            return -1;
429        }
430    }
431    return call ? 0 : -1;
432}
433
434
435void
436remote_call_cancel( const char*  to_number, int  from_port )
437{
438    remote_call_generic( REMOTE_CALL_HANGUP, to_number, from_port );
439}
440