This commit was generated by cvs2svn to compensate for changes in r164,
[gnokii.git] / gnokii / gnokii.c
1 /*
2
3   $Id$
4   
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Copyright (C) 1999, 2000 Hugh Blemings & Pavel Janík ml.
10   Copyright (C) 2001       Pavel Machek
11   Copyright (C) 2001       Pawe³ Kot
12
13   Released under the terms of the GNU GPL, see file COPYING for more details.
14         
15   Mainline code for gnokii utility.  Handles command line parsing and
16   reading/writing phonebook entries and other stuff.
17
18   WARNING: this code is the test tool. Well, our test tool is now
19   really powerful and useful :-)
20
21   $Log$
22   Revision 1.1.1.12  2002/04/03 01:44:15  short
23   Implemented connection type "tcp" (GCT_TCP), use <hostname>:<port> as "port"
24
25   Revision 1.1.1.11  2002/04/03 00:08:17  short
26   Found in "gnokii-working" directory, some November-patches version
27
28   Revision 1.143  2001/09/14 13:30:07  pkot
29   Fixed bugs introduced during 0.3.3 merge
30
31   Revision 1.142  2001/09/14 13:02:03  pkot
32   Gnokii calendar changes from 0.3.3
33
34   Revision 1.141  2001/09/14 12:53:00  pkot
35   New preview logos.
36   Localization fixes.
37   Set valid operator on logos xgnokii screen.
38
39   Revision 1.140  2001/07/27 00:02:21  pkot
40   Generic AT support for the new structure (Manfred Jonsson)
41
42   Revision 1.139  2001/07/01 23:16:45  pkot
43   Fixed a typo in gnokii.c avoiding saving logo (Jan Havelka)
44
45   Revision 1.138  2001/06/28 00:28:45  pkot
46   Small docs updates (Pawel Kot)
47
48   Revision 1.137  2001/06/27 23:52:50  pkot
49   7110/6210 updates (Marian Jancar)
50
51   Revision 1.136  2001/06/10 23:49:49  pkot
52   Small fixes to hide compilation warnings and allow gnokii.c to compile
53
54   Revision 1.135  2001/06/10 11:42:26  machek
55   Cleanup: some formating, made Statemachine global, converted to new
56   structure w.r.t. SMS-es
57
58   Revision 1.134  2001/05/24 20:47:30  chris
59   More updating of 7110 code and some of xgnokii_lowlevel changed over.
60
61   Revision 1.133  2001/04/23 17:20:01  pkot
62   Added possibility for viewing logos (currently nol and ngg) on console (Bartek Klepacz)
63
64   Revision 1.132  2001/03/21 23:36:06  chris
65   Added the statemachine
66   This will break gnokii --identify and --monitor except for 6210/7110
67
68   Revision 1.131  2001/03/19 23:43:46  pkot
69   Solaris / BSD '#if defined' cleanup
70
71   Revision 1.130  2001/03/13 01:23:18  pkot
72   Windows updates (Manfred Jonsson)
73
74   Revision 1.129  2001/03/13 01:21:39  pkot
75   *BSD updates (Bert Driehuis)
76
77   Revision 1.128  2001/03/08 00:49:06  pkot
78   Fixed bug (introduced by me) in getmemory function. Now gnokii.c should compile
79
80   Revision 1.127  2001/03/08 00:18:13  pkot
81   Fixed writephonebook once again. Someone kick me please...
82
83   Revision 1.126  2001/03/07 21:46:12  pkot
84   Fixed writephonebook patch
85
86   Revision 1.125  2001/03/06 22:19:14  pkot
87   Cleanups and fixes in gnokii.c:
88    - reindenting
89    - fixed bug reported by Gabriele Zappi
90    - fixed small bugs introduced by Pavel Machek
91
92   Revision 1.124  2001/02/28 21:42:00  machek
93   Possibility to force overwrite in --getsms (-F). Possibility to get
94   multiple files (use --getsms -f xyzzy%d), cleanup.
95
96   Revision 1.123  2001/02/20 21:55:11  pkot
97   Small #include updates
98
99   Revision 1.122  2001/02/16 14:29:53  chris
100   Restructure of common/.  Fixed a problem in fbus-phonet.c
101   Lots of dprintfs for Marcin
102   Any size xpm can now be loaded (eg for 7110 startup logos)
103   nk7110 code detects 7110/6210 and alters startup logo size to suit
104   Moved Marcin's extended phonebook code into gnokii.c
105
106   Revision 1.121  2001/02/06 21:15:35  chris
107   Preliminary irda support for 7110 etc.  Not well tested!
108
109   Revision 1.120  2001/02/06 08:13:32  pkot
110   One more include in gnokii.c needed
111
112   Revision 1.119  2001/02/05 12:29:37  pkot
113   Changes needed to let unicode work
114
115   Revision 1.118  2001/02/01 15:17:33  pkot
116   Fixed --identify and added Manfred's manufacturer patch
117
118   Revision 1.117  2001/01/31 23:45:27  pkot
119   --identify should work ok now
120
121   Revision 1.116  2001/01/24 20:19:55  machek
122   Do not retry identification, if it is not implemented, it is bad idea.
123
124   Revision 1.115  2001/01/22 01:25:10  hugh
125   Tweaks for 3810 series, datacalls seem to be broken so need to do
126   some more debugging...
127
128   Revision 1.114  2001/01/17 02:54:55  chris
129   More 7110 work.  Use with care! (eg it is not possible to delete phonebook entries)
130   I can now edit my phonebook in xgnokii but it is 'work in progress'.
131
132   Revision 1.113  2001/01/15 17:00:49  pkot
133   Initial keypress sequence support. Disable compilation warning
134
135   Revision 1.112  2001/01/12 14:09:13  pkot
136   More cleanups. This time mainly in the code.
137
138   Revision 1.111  2001/01/10 16:32:18  pkot
139   Documentation updates.
140   FreeBSD fix for 3810 code.
141   Added possibility for deleting SMS just after reading it in gnokii.
142   2110 code updates.
143   Many cleanups.
144
145   Revision 1.110  2001/01/08 15:11:37  pkot
146   Documentation updates.
147   Fixed some bugs and removed FIXMEs.
148   We need to move some stuff from configure.in to aclocal.m4
149
150   Revision 1.109  2000/12/29 15:39:07  pkot
151   Reverted a change in fbus-3810.c which broke compling with --enable-debug.
152   Small fixes in gnokii.c
153
154   Revision 1.108  2000/12/19 16:18:16  pkot
155   configure script updates and added shared function for configfile reading
156
157   
158 */
159
160 #include "config.h"
161 #include "misc.h"
162
163 #include <stdio.h>
164 #include <stdlib.h>
165 #include <signal.h>
166 #include <string.h>
167 #if __unices__
168 #  include <strings.h>  /* for memset */
169 #endif
170 #include <time.h>
171 #include <sys/types.h>
172 #include <sys/stat.h>
173
174 #ifdef WIN32
175
176 #include <windows.h>
177 #define sleep(x) Sleep((x) * 1000)
178 #define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
179 #define stat _stat
180 #include "win32/getopt.h"
181
182 #else
183
184 #include <unistd.h>
185 #include <termios.h>
186 #include <fcntl.h>
187 #include <getopt.h>
188
189 #endif
190
191 #ifdef USE_NLS
192 #include <locale.h>
193 #endif
194
195 #include "gsm-common.h"
196 #include "gsm-api.h"
197 #include "gsm-networks.h"
198 #include "cfgreader.h"
199 #include "gnokii.h"
200 #include "gsm-filetypes.h"
201 #include "gsm-bitmaps.h"
202 #include "gsm-ringtones.h"
203 #include "gsm-statemachine.h"
204
205 char *model;      /* Model from .gnokiirc file. */
206 char *Port;       /* Serial port from .gnokiirc file */
207 char *Initlength; /* Init length from .gnokiirc file */
208 char *Connection; /* Connection type from .gnokiirc file */
209 char *BinDir;     /* Binaries directory from .gnokiirc file - not used here yet */
210 /* Local variables */
211
212 char *GetProfileCallAlertString(int code)
213 {
214         switch (code) {
215         case PROFILE_CALLALERT_RINGING:         return "Ringing";
216         case PROFILE_CALLALERT_ASCENDING:       return "Ascending";
217         case PROFILE_CALLALERT_RINGONCE:        return "Ring once";
218         case PROFILE_CALLALERT_BEEPONCE:        return "Beep once";
219         case PROFILE_CALLALERT_CALLERGROUPS:    return "Caller groups";
220         case PROFILE_CALLALERT_OFF:             return "Off";
221         default:                                return "Unknown";
222         }
223 }
224
225 char *GetProfileVolumeString(int code)
226 {
227         switch (code) {
228         case PROFILE_VOLUME_LEVEL1:             return "Level 1";
229         case PROFILE_VOLUME_LEVEL2:             return "Level 2";
230         case PROFILE_VOLUME_LEVEL3:             return "Level 3";
231         case PROFILE_VOLUME_LEVEL4:             return "Level 4";
232         case PROFILE_VOLUME_LEVEL5:             return "Level 5";
233         default:                                return "Unknown";
234         }
235 }
236
237 char *GetProfileKeypadToneString(int code)
238 {
239         switch (code) {
240         case PROFILE_KEYPAD_OFF:                return "Off";
241         case PROFILE_KEYPAD_LEVEL1:             return "Level 1";
242         case PROFILE_KEYPAD_LEVEL2:             return "Level 2";
243         case PROFILE_KEYPAD_LEVEL3:             return "Level 3";
244         default:                                return "Unknown";
245         }
246 }
247
248 char *GetProfileMessageToneString(int code)
249 {
250         switch (code) {
251         case PROFILE_MESSAGE_NOTONE:            return "No tone";
252         case PROFILE_MESSAGE_STANDARD:          return "Standard";
253         case PROFILE_MESSAGE_SPECIAL:           return "Special";
254         case PROFILE_MESSAGE_BEEPONCE:          return "Beep once";
255         case PROFILE_MESSAGE_ASCENDING:         return "Ascending";
256         default:                                return "Unknown";
257         }
258 }
259
260 char *GetProfileWarningToneString(int code)
261 {
262         switch (code) {
263         case PROFILE_WARNING_OFF:               return "Off";
264         case PROFILE_WARNING_ON:                return "On";
265         default:                                return "Unknown";
266         }
267 }
268
269 char *GetProfileVibrationString(int code)
270 {
271         switch (code) {
272         case PROFILE_VIBRATION_OFF:             return "Off";
273         case PROFILE_VIBRATION_ON:              return "On";
274         default:                                return "Unknown";
275         }
276 }
277
278 /* This function shows the copyright and some informations usefull for
279    debugging. */
280
281 int version(void)
282 {
283         fprintf(stdout, _("GNOKII Version %s\n"
284                           "Copyright (C) Hugh Blemings <hugh@blemings.org>, 1999, 2000\n"
285                           "Copyright (C) Pavel Janík ml. <Pavel.Janik@suse.cz>, 1999, 2000\n"
286                           "Copyright (C) Pavel Machek <pavel@ucw.cz>, 2001\n"
287                           "Copyright (C) Pawe³ Kot <pkot@linuxnews.pl>, 2001\n"
288                           "gnokii is free software, covered by the GNU General Public License, and you are\n"
289                           "welcome to change it and/or distribute copies of it under certain conditions.\n"
290                           "There is absolutely no warranty for gnokii.  See GPL for details.\n"
291                           "Built %s %s for %s on %s \n"), VERSION, __TIME__, __DATE__, model, Port);
292         return 0;
293 }
294
295 /* The function usage is only informative - it prints this program's usage and
296    command-line options. */
297
298 int usage(void)
299 {
300         fprintf(stdout, _("   usage: gnokii [--help|--monitor|--version]\n"
301                           "          gnokii --getmemory memory_type start [end]\n"
302                           "          gnokii --writephonebook [-i]\n"
303                           "          gnokii --getspeeddial number\n"
304                           "          gnokii --setspeeddial number memory_type location\n"
305                           "          gnokii --getsms memory_type start [end] [-f file] [-F file] [-d]\n"
306                           "          gnokii --deletesms memory_type start [end]\n"
307                           "          gnokii --sendsms destination [-r] [-C n] [-v n]\n"
308                           "                 [--longtext|--longudh] [--udh] [-8]\n"
309                           "                 [--smsc message_center_number | --smscno message_center_index]\n"
310                           "          gnokii --savesms [-m] [-l n] [-i]\n"
311                           "          gnokii --getsmsc message_center_number\n"
312                           "          gnokii --setdatetime [YYYY [MM [DD [HH [MM]]]]]\n"
313                           "          gnokii --getdatetime\n"
314                           "          gnokii --setalarm HH MM\n"
315                           "          gnokii --getalarm\n"
316                           "          gnokii --dialvoice number\n"
317                           "          gnokii --getcalendarnote start [end] [-v]\n"
318                           "          gnokii --writecalendarnote vcardfile number\n"
319                           "          gnokii --deletecalendarnote start [end]\n"
320                           "          gnokii --getdisplaystatus\n"
321                           "          gnokii --netmonitor {reset|off|field|devel|next|nr}\n"
322                           "          gnokii --identify\n"
323                           "          gnokii --senddtmf string\n"
324                           "          gnokii --sendlogo {caller|op} destination logofile [network code]\n"
325                           "                 [--smsc message_center_number | --smscno message_center_index]\n"
326                           "          gnokii --sendringtone destination rtttlfile\n"
327                           "                 [--smsc message_center_number | --smscno message_center_index]\n"
328                           "          gnokii --setlogo op [logofile] [network code]\n"
329                           "          gnokii --setlogo startup [logofile]\n"
330                           "          gnokii --setlogo caller [logofile] [caller group number] [group name]\n"
331                           "          gnokii --setlogo {dealer|text} [text]\n"
332                           "          gnokii --getlogo op [logofile] [network code]\n"
333                           "          gnokii --getlogo startup [logofile] [network code]\n"
334                           "          gnokii --getlogo caller [logofile][caller group number][network code]\n"
335                           "          gnokii --getlogo {dealer|text}\n"
336                           "          gnokii --viewlogo logofile\n"
337                           "          gnokii --setringtone rtttlfile\n"
338                           "          gnokii --reset [soft|hard]\n"
339                           "          gnokii --getprofile [number]\n"
340                           "          gnokii --displayoutput\n"
341                           "          gnokii --keysequence\n"
342                 ));
343 #ifdef SECURITY
344         fprintf(stdout, _(
345                 "          gnokii --entersecuritycode PIN|PIN2|PUK|PUK2\n"
346                 "          gnokii --getsecuritycodestatus\n"
347                 ));
348 #endif
349         exit(-1);
350 }
351
352 /* fbusinit is the generic function which waits for the FBUS link. The limit
353    is 10 seconds. After 10 seconds we quit. */
354
355 static GSM_Statemachine State;
356 static GSM_Data data;
357
358 void fbusinit(void (*rlp_handler)(RLP_F96Frame *frame))
359 {
360         int count=0;
361         GSM_Error error;
362         GSM_ConnectionType connection=GCT_Serial;
363
364         GSM_DataClear(&data);
365
366         if (!strcmp(Connection, "infrared")) connection=GCT_Infrared;
367         if (!strcmp(Connection, "irda"))     connection=GCT_Irda;
368         if (!strcmp(Connection, "tcp"))      connection=GCT_TCP;
369
370         /* Initialise the code for the GSM interface. */     
371
372         error = GSM_Initialise(model, Port, Initlength, connection, rlp_handler, &State);
373
374         if (error != GE_NONE) {
375                 fprintf(stderr, _("GSM/FBUS init failed! (Unknown model ?). Quitting.\n"));
376                 exit(-1);
377         }
378
379         /* First (and important!) wait for GSM link to be active. We allow 10
380            seconds... */
381
382         while (count++ < 200 && *GSM_LinkOK == false)
383                 usleep(50000);
384
385         if (*GSM_LinkOK == false) {
386                 fprintf (stderr, _("Hmmm... GSM_LinkOK never went true. Quitting.\n"));
387                 exit(-1);
388         }
389 }
390
391 /* This function checks that the argument count for a given options is withing
392    an allowed range. */
393 int checkargs(int opt, struct gnokii_arg_len gals[], int argc)
394 {
395         int i;
396
397         /* Walk through the whole array with options requiring arguments. */
398         for (i = 0; !(gals[i].gal_min == 0 && gals[i].gal_max == 0); i++) {
399
400                 /* Current option. */
401                 if (gals[i].gal_opt == opt) {
402
403                         /* Argument count checking. */
404                         if (gals[i].gal_flags == GAL_XOR) {
405                                 if (gals[i].gal_min == argc || gals[i].gal_max == argc)
406                                         return 0;
407                         } else {
408                                 if (gals[i].gal_min <= argc && gals[i].gal_max >= argc)
409                                         return 0;
410                         }
411
412                         return 1;
413                 }
414         }
415
416         /* We do not have options without arguments in the array, so check them. */
417         if (argc == 0) return 0;
418         else return 1;
419 }
420
421 /* Main function - handles command line arguments, passes them to separate
422    functions accordingly. */
423 int main(int argc, char *argv[])
424 {
425         int c, i, rc = -1;
426         int nargc = argc-2;
427         char **nargv;
428
429         /* Every option should be in this array. */
430         static struct option long_options[] =
431         {
432                 /* FIXME: these comments are nice, but they would be more usefull as docs for the user */
433                 // Display usage.
434                 { "help",               no_argument,       NULL, OPT_HELP },
435
436                 // Display version and build information.
437                 { "version",            no_argument,       NULL, OPT_VERSION },
438
439                 // Monitor mode
440                 { "monitor",            no_argument,       NULL, OPT_MONITOR },
441
442 #ifdef SECURITY
443
444                 // Enter Security Code mode
445                 { "entersecuritycode",  required_argument, NULL, OPT_ENTERSECURITYCODE },
446
447                 // Get Security Code status
448                 { "getsecuritycodestatus",  no_argument,   NULL, OPT_GETSECURITYCODESTATUS },
449
450 #endif
451
452                 // Set date and time
453                 { "setdatetime",        optional_argument, NULL, OPT_SETDATETIME },
454
455                 // Get date and time mode
456                 { "getdatetime",        no_argument,       NULL, OPT_GETDATETIME },
457
458                 // Set alarm
459                 { "setalarm",           required_argument, NULL, OPT_SETALARM },
460
461                 // Get alarm
462                 { "getalarm",           no_argument,       NULL, OPT_GETALARM },
463
464                 // Voice call mode
465                 { "dialvoice",          required_argument, NULL, OPT_DIALVOICE },
466
467                 // Get calendar note mode
468                 { "getcalendarnote",    required_argument, NULL, OPT_GETCALENDARNOTE },
469
470                 // Write calendar note mode
471                 { "writecalendarnote",  required_argument, NULL, OPT_WRITECALENDARNOTE },
472
473                 // Delete calendar note mode
474                 { "deletecalendarnote", required_argument, NULL, OPT_DELCALENDARNOTE },
475
476                 // Get display status mode
477                 { "getdisplaystatus",   no_argument,       NULL, OPT_GETDISPLAYSTATUS },
478
479                 // Get memory mode
480                 { "getmemory",          required_argument, NULL, OPT_GETMEMORY },
481
482                 // Write phonebook (memory) mode
483                 { "writephonebook",     optional_argument, NULL, OPT_WRITEPHONEBOOK },
484
485                 // Get speed dial mode
486                 { "getspeeddial",       required_argument, NULL, OPT_GETSPEEDDIAL },
487
488                 // Set speed dial mode
489                 { "setspeeddial",       required_argument, NULL, OPT_SETSPEEDDIAL },
490
491                 // Get SMS message mode
492                 { "getsms",             required_argument, NULL, OPT_GETSMS },
493
494                 // Delete SMS message mode
495                 { "deletesms",          required_argument, NULL, OPT_DELETESMS },
496
497                 // Send SMS message mode
498                 { "sendsms",            required_argument, NULL, OPT_SENDSMS },
499
500                 // Save SMS message mode
501                 { "savesms",            optional_argument, NULL, OPT_SAVESMS },
502
503                 // Send logo as SMS message mode
504                 { "sendlogo",           required_argument, NULL, OPT_SENDLOGO },
505
506                 // Send ringtone as SMS message
507                 { "sendringtone",       required_argument, NULL, OPT_SENDRINGTONE },
508
509                 // Set ringtone
510                 { "setringtone",        required_argument, NULL, OPT_SETRINGTONE },
511
512                 // Get SMS center number mode
513                 { "getsmsc",            required_argument, NULL, OPT_GETSMSC },
514
515                 // For development purposes: run in passive monitoring mode
516                 { "pmon",               no_argument,       NULL, OPT_PMON },
517
518                 // NetMonitor mode
519                 { "netmonitor",         required_argument, NULL, OPT_NETMONITOR },
520
521                 // Identify
522                 { "identify",           no_argument,       NULL, OPT_IDENTIFY },
523
524                 // Send DTMF sequence
525                 { "senddtmf",           required_argument, NULL, OPT_SENDDTMF },
526
527                 // Resets the phone
528                 { "reset",              optional_argument, NULL, OPT_RESET },
529
530                 // Set logo
531                 { "setlogo",            optional_argument, NULL, OPT_SETLOGO },
532
533                 // Get logo
534                 { "getlogo",            required_argument, NULL, OPT_GETLOGO },
535
536                 // View logo
537                 { "viewlogo",           required_argument, NULL, OPT_VIEWLOGO },
538
539                 // Show profile
540                 { "getprofile",         optional_argument, NULL, OPT_GETPROFILE },
541
542                 // Show texts from phone's display
543                 { "displayoutput",      no_argument,       NULL, OPT_DISPLAYOUTPUT },
544
545                 // Simulate pressing the keys
546                 { "keysequence",        no_argument,       NULL, OPT_KEYPRESS },
547     
548                 // For development purposes: insert you function calls here
549                 { "foogle",             no_argument,       NULL, OPT_FOOGLE },
550
551                 { 0, 0, 0, 0},
552         };
553
554         /* Every command which requires arguments should have an appropriate entry
555            in this array. */
556         struct gnokii_arg_len gals[] =
557         {
558
559 #ifdef SECURITY
560                 { OPT_ENTERSECURITYCODE, 1, 1, 0 },
561 #endif
562
563                 { OPT_SETDATETIME,       0, 5, 0 },
564                 { OPT_SETALARM,          2, 2, 0 },
565                 { OPT_DIALVOICE,         1, 1, 0 },
566                 { OPT_GETCALENDARNOTE,   1, 3, 0 },
567                 { OPT_WRITECALENDARNOTE, 2, 2, 0 },
568                 { OPT_DELCALENDARNOTE,   1, 2, 0 },
569                 { OPT_GETMEMORY,         2, 3, 0 },
570                 { OPT_GETSPEEDDIAL,      1, 1, 0 },
571                 { OPT_SETSPEEDDIAL,      3, 3, 0 },
572                 { OPT_GETSMS,            2, 5, 0 },
573                 { OPT_DELETESMS,         2, 3, 0 },
574                 { OPT_SENDSMS,           1, 10, 0 },
575                 { OPT_SAVESMS,           0, 6, 0 },
576                 { OPT_SENDLOGO,          3, 6, 0 },
577                 { OPT_SENDRINGTONE,      2, 6, 0 },
578                 { OPT_GETSMSC,           1, 1, 0 },
579                 { OPT_GETWELCOMENOTE,    1, 1, 0 },
580                 { OPT_SETWELCOMENOTE,    1, 1, 0 },
581                 { OPT_NETMONITOR,        1, 1, 0 },
582                 { OPT_SENDDTMF,          1, 1, 0 },
583                 { OPT_SETLOGO,           1, 4, 0 },
584                 { OPT_GETLOGO,           1, 4, 0 },
585                 { OPT_VIEWLOGO,          1, 1, 0 },
586                 { OPT_SETRINGTONE,       1, 1, 0 },
587                 { OPT_RESET,             0, 1, 0 },
588                 { OPT_GETPROFILE,        0, 1, 0 },
589                 { OPT_WRITEPHONEBOOK,    0, 1, 0 },
590
591                 { 0, 0, 0, 0 },
592         };
593
594         opterr = 0;
595
596         /* For GNU gettext */
597 #ifdef USE_NLS
598         textdomain("gnokii");
599         setlocale(LC_ALL, "");
600 #endif
601
602         /* Read config file */
603         if (readconfig(&model, &Port, &Initlength, &Connection, &BinDir) < 0) {
604                 exit(-1);
605         }
606
607         /* Handle command line arguments. */
608         c = getopt_long(argc, argv, "", long_options, NULL);
609         if (c == -1)            /* No argument given - we should display usage. */
610                 usage();
611
612         switch(c) {
613         // First, error conditions
614         case '?':
615         case ':':
616                 fprintf(stderr, _("Use '%s --help' for usage informations.\n"), argv[0]);
617                 exit(0);
618         // Then, options with no arguments
619         case OPT_HELP:
620                 usage();
621         case OPT_VERSION:
622                 return version();
623         }
624         
625         /* We have to build an array of the arguments which will be passed to the
626            functions.  Please note that every text after the --command will be
627            passed as arguments.  A syntax like gnokii --cmd1 args --cmd2 args will
628            not work as expected; instead args --cmd2 args is passed as a
629            parameter. */
630         if ((nargv = malloc(sizeof(char *) * argc)) != NULL) {
631                 for (i = 2; i < argc; i++)
632                         nargv[i-2] = argv[i];
633         
634                 if (checkargs(c, gals, nargc)) {
635                         free(nargv); /* Wrong number of arguments - we should display usage. */
636                         usage();
637                 }
638
639 #ifdef __svr4__
640                 /* have to ignore SIGALARM */
641                 sigignore(SIGALRM);
642 #endif
643
644                 /* Initialise the code for the GSM interface. */     
645                 fbusinit(NULL);
646
647                 switch(c) {
648                 case OPT_MONITOR:
649                         rc = monitormode();
650                         break;
651 #ifdef SECURITY
652                 case OPT_ENTERSECURITYCODE:
653                         rc = entersecuritycode(optarg);
654                         break;
655                 case OPT_GETSECURITYCODESTATUS:
656                         rc = getsecuritycodestatus();
657                         break;
658 #endif
659                 case OPT_GETDATETIME:
660                         rc = getdatetime();
661                         break;
662                 case OPT_GETALARM:
663                         rc = getalarm();
664                         break;
665                 case OPT_GETDISPLAYSTATUS:
666                         rc = getdisplaystatus();
667                         break;
668                 case OPT_PMON:
669                         rc = pmon();
670                         break;
671                 case OPT_WRITEPHONEBOOK:
672                         rc = writephonebook(nargc, nargv);
673                         break;
674                 // Now, options with arguments
675                 case OPT_SETDATETIME:
676                         rc = setdatetime(nargc, nargv);
677                         break;
678                 case OPT_SETALARM:
679                         rc = setalarm(nargv);
680                         break;
681                 case OPT_DIALVOICE:
682                         rc = dialvoice(optarg);
683                         break;
684                 case OPT_GETCALENDARNOTE:
685                         rc = getcalendarnote(nargc, nargv);
686                         break;
687                 case OPT_DELCALENDARNOTE:
688                         rc = deletecalendarnote(nargc, nargv);
689                         break;
690                 case OPT_WRITECALENDARNOTE:
691                         rc = writecalendarnote(nargv);
692                         break;
693                 case OPT_GETMEMORY:
694                         rc = getmemory(nargc, nargv);
695                         break;
696                 case OPT_GETSPEEDDIAL:
697                         rc = getspeeddial(optarg);
698                         break;
699                 case OPT_SETSPEEDDIAL:
700                         rc = setspeeddial(nargv);
701                         break;
702                 case OPT_GETSMS:
703                         rc = getsms(argc, argv);
704                         break;
705                 case OPT_DELETESMS:
706                         rc = deletesms(nargc, nargv);
707                         break;
708                 case OPT_SENDSMS:
709                         rc = sendsms(nargc, nargv);
710                         break;
711                 case OPT_SAVESMS:
712                         rc = savesms(argc, argv);
713                         break;
714                 case OPT_SENDLOGO:
715                         rc = sendlogo(nargc, nargv);
716                         break;
717                 case OPT_GETSMSC:
718                         rc = getsmsc(optarg);
719                         break;
720                 case OPT_NETMONITOR:
721                         rc = netmonitor(optarg);
722                         break;
723                 case OPT_IDENTIFY:
724                         rc = identify();
725                         break;
726                 case OPT_SETLOGO:
727                         rc = setlogo(nargc, nargv);
728                         break;
729                 case OPT_GETLOGO:
730                         rc = getlogo(nargc, nargv);
731                         break;
732                 case OPT_VIEWLOGO:
733                         rc = viewlogo(optarg);
734                         break;
735                 case OPT_SETRINGTONE:
736                         rc = setringtone(nargc, nargv);
737                         break;
738                 case OPT_SENDRINGTONE:
739                         rc = sendringtone(argc, argv);
740                         break;
741                 case OPT_GETPROFILE:
742                         rc = getprofile(nargc, nargv);
743                         break;
744                 case OPT_DISPLAYOUTPUT:
745                         rc = displayoutput();
746                         break;
747                 case OPT_KEYPRESS:
748                         rc = presskeysequence();
749                         break;
750 #ifndef WIN32
751                 case OPT_FOOGLE:
752                         rc = foogle(nargv);
753                         break;
754 #endif
755                 case OPT_SENDDTMF:
756                         rc = senddtmf(optarg);
757                         break;
758                 case OPT_RESET:
759                         rc = reset(optarg);
760                         break;
761                 default:
762                         fprintf(stderr, _("Unknown option: %d\n"), c);
763                         break;
764
765                 }
766                 return(rc);
767         }
768
769         fprintf(stderr, _("Wrong number of arguments\n"));
770         exit(-1);
771 }
772
773 #define SMSC_SHORTCHAR_SMSC   (0xF0)
774 #define SMSC_SHORTCHAR_SMSCNO (0xF1)
775 #define SMSC_OPTIONS \
776                 { "smsc",     required_argument, NULL, SMSC_SHORTCHAR_SMSC}, \
777                 { "smscno",   required_argument, NULL, SMSC_SHORTCHAR_SMSCNO}
778
779 /* RETURNS: Whether the options was found as ours (=>rerun getopt_long())
780  */
781 static bool smsc_options_parse(int option,GSM_SMSMessage *SMS)
782 {
783         switch (option) {
784
785         case SMSC_SHORTCHAR_SMSC: /* SMSC number */
786                 SMS->MessageCenter.No = 0;
787                 strcpy(SMS->MessageCenter.Number,optarg);
788                 break;
789
790         case SMSC_SHORTCHAR_SMSCNO: /* SMSC number index in phone memory */
791                 SMS->MessageCenter.No = atoi(optarg);
792
793                 if (SMS->MessageCenter.No < 1 || SMS->MessageCenter.No > 5)
794                         usage();
795                 break;
796
797         default:
798                 return(false);          /* option not recognized */
799         }
800
801         return(true);   /* option was successfuly processed */
802 }
803
804 /* RETURNS: Success
805  */
806 bool sendsms_deconcatenated(GSM_SMSMessage *sms,char *buf,size_t buflen,bool useudh)
807 {
808         GSM_Deconcatenate_state SMS_Deconcatenate_state;
809         GSM_Error error;
810
811         SMS_Deconcatenate_state.first=true;
812         while (SMS_Deconcatenate(&SMS_Deconcatenate_state,sms,buf,buflen,useudh)) {
813                 /* Send the message. */
814                 error = GSM->SendSMSMessage(sms);
815
816                 if (error == GE_SMSSENDOK) {
817                         fprintf(stdout, _("Send succeeded!\n"));
818                 } else {
819                         fprintf(stdout, _("SMS Send failed (error=%d)\n"), error);
820                         return(false);
821                 }
822                 /* Here the sleep have no meaning.
823                  * If it is required by some backend phone driver, it should be done THERE!
824                  */
825                 /* sleep(10); */
826         }
827         return(true);
828 }
829
830 /* Send  SMS messages. */
831 int sendsms(int argc, char *argv[])
832 {
833         GSM_SMSMessage SMS;
834         /* The maximum length of an uncompressed concatenated short message is
835            255 * 153 = 39015 default alphabet characters */
836         char message_buffer[GSM_MAX_CONCATENATED_SMS_LENGTH];
837         int input_len, chars_read;
838         int i;
839         bool useudh = false;
840
841         struct option options[] = {
842                 SMSC_OPTIONS,
843                 { "longtext", no_argument,       NULL, '3'},
844                 { "longudh",  no_argument,       NULL, '4'},
845                 { "udh",      no_argument,       NULL, '5'},
846                 { NULL,       0,                 NULL, 0}
847         };
848
849         input_len = GSM_MAX_SMS_LENGTH;
850
851         /* Default settings:
852            - no delivery report
853            - no Class Message
854            - no compression
855            - 7 bit data
856            - SMSC no. 1
857            - message validity for 3 days
858            - unset user data header indicator
859         */
860
861         SMS.Type = GST_MO;
862         SMS.Class = -1;
863         SMS.Compression = false;
864         SMS.EightBit = false;
865         SMS.MessageCenter.No = 1;
866         SMS.Validity = 4320; /* 4320 minutes == 72 hours */
867         SMS.UDHPresent = false;
868
869         strcpy(SMS.Destination, argv[0]);
870
871         optarg = NULL;
872         optind = 0;
873
874         while ((i = getopt_long(argc, argv, "r8cC:v:", options, NULL)) != -1) {
875                 if (smsc_options_parse(i,&SMS))
876                         continue;
877                 switch (i) {       // -c for compression. not yet implemented.
878                 case '3': /* we send long message in text format */
879                         input_len = GSM_MAX_CONCATENATED_SMS_LENGTH;
880                         useudh = false;
881                         break;
882                 case '4': /* we send long message in UDH format */
883                         input_len = GSM_MAX_CONCATENATED_SMS_LENGTH;
884                         useudh = true;
885                         break;
886                 case '5': /* UDH indication requested */
887                         SMS.UDHPresent = true;
888                         break;
889                 case 'r': /* request for delivery report */
890                         SMS.Type = GST_DR;
891                         break;
892                 case 'C': /* class Message */
893                         switch (*optarg) {
894                         case '0':
895                                 SMS.Class = 0;
896                                 break;
897                         case '1':
898                                 SMS.Class = 1;
899                                 break;
900                         case '2':
901                                 SMS.Class = 2;
902                                 break;
903                         case '3':
904                                 SMS.Class = 3;
905                                 break;
906                         default:
907                                 usage();
908                         }
909                         break;
910                 case '8': /* 8-bit data */
911                         SMS.EightBit = true;
912                         break;
913                 case 'v':
914                         SMS.Validity = atoi(optarg);
915                         break;
916                 default:
917                         usage(); /* Would be better to have an sendsms_usage() here. */
918                 }
919         }
920
921         /* Get message text from stdin. */
922         chars_read = fread(message_buffer, 1, input_len, stdin);
923
924         if (chars_read == 0) {
925                 fprintf(stderr, _("Couldn't read from stdin!\n"));      
926                 return -1;
927         } else if (chars_read > input_len) {
928                 fprintf(stderr, _("Input too long!\n"));        
929                 return -1;
930         }
931
932         if (SMS.UDHPresent) {
933 u8 UDHlen = 1 + message_buffer[0];      /* designifify */
934
935                 if (chars_read < UDHlen || sizeof(SMS.UDH) < UDHlen) {
936                         fprintf(stderr, _("Input too short to satisfy UDH!\n"));
937                         return -1;
938                 }
939                 memcpy(SMS.UDH, message_buffer, UDHlen);
940                 chars_read-=UDHlen;
941                 memmove(message_buffer, message_buffer + UDHlen, chars_read);
942         }
943
944         /*  Null terminate. */
945         message_buffer[chars_read] = 0x00;      
946
947         sendsms_deconcatenated(&SMS,message_buffer,chars_read,useudh);
948
949         GSM->Terminate();
950
951         return 0;
952 }
953
954 int savesms(int argc, char *argv[])
955 {
956         GSM_SMSMessage SMS;
957         GSM_Error error;
958         /* The maximum length of an uncompressed concatenated short message is
959            255 * 153 = 39015 default alphabet characters */
960         char message_buffer[GSM_MAX_CONCATENATED_SMS_LENGTH];
961         int input_len, chars_read;
962         int i, confirm = -1;
963         int interactive = 0;
964         char ans[8];
965
966         /* Defaults */
967         SMS.Type = GST_MO;
968         SMS.Destination[0] = '\0';
969         SMS.Class = -1;
970         SMS.Compression = false;
971         SMS.EightBit = false;
972         SMS.MessageCenter.No = 1;
973         SMS.Validity = 4320; /* 4320 minutes == 72 hours */
974         SMS.UDHPresent = false;
975         SMS.Status = GSS_NOTSENTREAD;
976         SMS.Location = 0;
977         SMS.MemoryType = GMT_SM;
978
979         input_len = GSM_MAX_SMS_LENGTH;
980
981         /* Option parsing */
982         while ((i = getopt(argc, argv, "ml:in:s:c:")) != -1) {
983                 switch (i) {
984                 case 'm': /* mark the message as sent */
985                         SMS.Status = GSS_SENTREAD;
986                         break;
987                 case 'l': /* Specify the location */
988                         SMS.Location = atoi(optarg);
989                         break;
990                 case 'i': /* Ask before overwriting */
991                         interactive = 1;
992                         break;
993                 case 'n': /* Specify the from number */
994                         break;
995                 case 's': /* Specify the smsc number */
996                         break;
997                 case 'c': /* Specify the smsc location */
998                         break;
999                 default:
1000                         usage();
1001                         return -1;
1002                 }
1003         }
1004
1005         if (interactive) {
1006                 GSM_SMSMessage aux;
1007
1008                 aux.Location = SMS.Location;
1009                 data.SMSMessage = &aux;
1010                 error = SM_Functions(GOP_GetSMS, &data, &State);
1011                 switch (error) {
1012                 case GE_NONE:
1013                         fprintf(stderr, _("Message at specified location exists. "));
1014                         while (confirm < 0) {
1015                                 fprintf(stderr, _("Overwrite? (yes/no) "));
1016                                 GetLine(stdin, ans, 7);
1017                                 if (!strcmp(ans, "yes")) confirm = 1;
1018                                 else if (!strcmp(ans, "no")) confirm = 0;
1019                         }  
1020                         if (!confirm) { GSM->Terminate(); return 0; }
1021                         else break;
1022                 case GE_INVALIDSMSLOCATION:
1023                         fprintf(stderr, _("Invalid location\n"));
1024                         GSM->Terminate();
1025                         return -1;
1026                 default:
1027 /* FIXME: Remove this fprintf when the function is thoroughly tested */
1028 #ifdef DEBUG
1029                         fprintf(stderr, _("Location %d empty. Saving\n"), SMS.Location);
1030 #endif
1031                         break;
1032                 }
1033         }
1034         chars_read = fread(message_buffer, 1, input_len, stdin);
1035
1036         if (chars_read == 0) {
1037
1038                 fprintf(stderr, _("Couldn't read from stdin!\n"));
1039                 return -1;
1040
1041         } else if (chars_read > input_len) {
1042
1043                 fprintf(stderr, _("Input too long!\n"));
1044                 return -1;
1045
1046         }
1047
1048         strncpy (SMS.MessageText, message_buffer, chars_read);
1049         SMS.MessageText[chars_read] = 0;
1050         SMS.MessageTextLength=chars_read;
1051
1052         error = GSM->SaveSMSMessage(&SMS);
1053
1054         if (error == GE_NONE) {
1055                 fprintf(stdout, _("Saved!\n"));
1056         } else {
1057                 fprintf(stdout, _("Saving failed (error=%d)\n"), error);
1058         }
1059         sleep(10);
1060         GSM->Terminate();
1061
1062         return 0;
1063 }
1064
1065 /* Get SMSC number */
1066 int getsmsc(char *MessageCenterNumber)
1067 {
1068         GSM_MessageCenter       MessageCenter;
1069         GSM_Data                data;
1070         GSM_Error               error;
1071         
1072         memset(&MessageCenter, 0, sizeof(MessageCenter));
1073         MessageCenter.No=atoi(MessageCenterNumber);
1074         
1075         if (GSM && GSM->GetSMSCenter && GSM->Terminate) {
1076                 error = GSM->GetSMSCenter(&MessageCenter);
1077                 GSM->Terminate();
1078         } else {
1079                 GSM_DataClear(&data);
1080                 data.MessageCenter = &MessageCenter;
1081                 error = SM_Functions(GOP_GetSMSCenter, &data, &State);
1082         }
1083         
1084         switch (error) {
1085         case GE_NONE:
1086                 fprintf(stdout, _("%d. SMS center (%s) number is %s\n"), MessageCenter.No, MessageCenter.Name, MessageCenter.Number);
1087                 fprintf(stdout, _("Default recipient number is %s\n"), MessageCenter.Recipient);
1088                 fprintf(stdout, _("Messages sent as "));
1089                 
1090                 switch (MessageCenter.Format) {
1091                 case GSMF_Text:
1092                         fprintf(stdout, _("Text"));
1093                         break;
1094                 case GSMF_Paging:
1095                         fprintf(stdout, _("Paging"));
1096                         break;
1097                 case GSMF_Fax:
1098                         fprintf(stdout, _("Fax"));
1099                         break;
1100                 case GSMF_Email:
1101                 case GSMF_UCI:
1102                         fprintf(stdout, _("Email"));
1103                         break;
1104                 case GSMF_ERMES:
1105                         fprintf(stdout, _("ERMES"));
1106                         break;
1107                 case GSMF_X400:
1108                         fprintf(stdout, _("X.400"));
1109                         break;
1110                 default:
1111                         fprintf(stdout, _("Unknown"));
1112                         break;
1113                 }
1114                 
1115                 printf("\n");
1116                 fprintf(stdout, _("Message validity is "));
1117                 
1118                 switch (MessageCenter.Validity) {
1119                 case GSMV_1_Hour:
1120                         fprintf(stdout, _("1 hour"));
1121                         break;
1122                 case GSMV_6_Hours:
1123                         fprintf(stdout, _("6 hours"));
1124                         break;
1125                 case GSMV_24_Hours:
1126                         fprintf(stdout, _("24 hours"));
1127                         break;
1128                 case GSMV_72_Hours:
1129                         fprintf(stdout, _("72 hours"));
1130                         break;
1131                 case GSMV_1_Week:
1132                         fprintf(stdout, _("1 week"));
1133                         break;
1134                 case GSMV_Max_Time:
1135                         fprintf(stdout, _("Maximum time"));
1136                         break;
1137                 default:
1138                         fprintf(stdout, _("Unknown"));
1139                         break;
1140                 }
1141                 
1142                 fprintf(stdout, "\n");
1143                 
1144                 break;
1145         case GE_NOTIMPLEMENTED:
1146                 fprintf(stderr, _("Function not implemented in %s model!\n"), model);
1147                 break;
1148         default:
1149                 fprintf(stdout, _("SMS center can not be found :-(\n"));
1150                 break;
1151         }
1152         
1153         return error;
1154 }
1155
1156 /* Get SMS messages. */
1157 int getsms(int argc, char *argv[])
1158 {
1159         int del = 0;
1160         GSM_SMSMessage message;
1161         char *memory_type_string;
1162         int start_message, end_message, count, mode = 1;
1163         char filename[64];
1164         GSM_Error error;
1165         GSM_Bitmap bitmap;
1166         char ans[5];
1167         struct stat buf;
1168
1169         /* Handle command line args that set type, start and end locations. */
1170         memory_type_string = argv[2];
1171         message.MemoryType = StrToMemoryType(memory_type_string);
1172         if (message.MemoryType == GMT_XX) {
1173                 fprintf(stderr, _("Unknown memory type %s (use ME, SM, ...)!\n"), argv[2]);
1174                 return (-1);
1175         }
1176
1177         memset(&filename, 0, 64);
1178
1179         start_message = end_message = atoi(argv[3]);
1180         if (argc > 4) {
1181                 int i;
1182
1183                 /* [end] can be only argv[4] */
1184                 if (argv[4][0] != '-') {
1185                         end_message = atoi(argv[4]);
1186                 }
1187
1188                 /* parse all options (beginning with '-' */
1189                 while ((i = getopt(argc, argv, "f:F:d")) != -1) {
1190                         switch (i) {
1191                         case 'd':
1192                                 del = 1;
1193                                 break;
1194                         case 'F':
1195                                 mode = 0;
1196                         case 'f':
1197                                 if (optarg) {
1198                                         dprintf(_("Saving into %s\n"), optarg);
1199                                         strncpy(filename, optarg, 64);
1200                                         if (strlen(optarg) > 63) {
1201                                                 fprintf(stderr, _("Filename too long - will be truncated to 63 characters.\n"));
1202                                                 filename[63] = 0;
1203                                         } else {
1204                                                 filename[strlen(optarg)] = 0;
1205                                         }
1206                                 } else  usage();
1207                                 break;
1208                         default:
1209                                 usage();
1210                         }
1211                 }
1212         }
1213
1214         /* Now retrieve the requested entries. */
1215         for (count = start_message; count <= end_message; count ++) {
1216
1217                 message.Location = count;
1218                 data.SMSMessage = &message;
1219                 error = SM_Functions(GOP_GetSMS, &data, &State);
1220
1221                 switch (error) {
1222                 case GE_NONE:
1223                         switch (message.Type) {
1224                         case GST_MO:
1225                                 fprintf(stdout, _("%d. Outbox Message "), message.MessageNumber);
1226                                 if (message.Status)
1227                                         fprintf(stdout, _("(sent)\n"));
1228                                 else
1229                                         fprintf(stdout, _("(not sent)\n"));
1230                                 fprintf(stdout, _("Text: %s\n\n"), message.MessageText); 
1231                                 break;
1232                         case GST_DR:
1233                                 fprintf(stdout, _("%d. Delivery Report "), message.MessageNumber);
1234                                 if (message.Status)
1235                                         fprintf(stdout, _("(read)\n"));
1236                                 else
1237                                         fprintf(stdout, _("(not read)\n"));
1238                                 fprintf(stdout, _("Sending date/time: %d/%d/%d %d:%02d:%02d "), \
1239                                         message.Time.Day, message.Time.Month, message.Time.Year, \
1240                                         message.Time.Hour, message.Time.Minute, message.Time.Second);
1241                                 if (message.Time.Timezone) {
1242                                         if (message.Time.Timezone > 0)
1243                                                 fprintf(stdout,_("+%02d00"), message.Time.Timezone);
1244                                         else
1245                                                 fprintf(stdout,_("%02d00"), message.Time.Timezone);
1246                                 }
1247                                 fprintf(stdout, "\n");
1248                                 fprintf(stdout, _("Response date/time: %d/%d/%d %d:%02d:%02d "), \
1249                                         message.SMSCTime.Day, message.SMSCTime.Month, message.SMSCTime.Year, \
1250                                         message.SMSCTime.Hour, message.SMSCTime.Minute, message.SMSCTime.Second);
1251                                 if (message.SMSCTime.Timezone) {
1252                                         if (message.SMSCTime.Timezone > 0)
1253                                                 fprintf(stdout,_("+%02d00"),message.SMSCTime.Timezone);
1254                                         else
1255                                                 fprintf(stdout,_("%02d00"),message.SMSCTime.Timezone);
1256                                 }
1257                                 fprintf(stdout, "\n");
1258                                 fprintf(stdout, _("Receiver: %s Msg Center: %s\n"), message.Sender, message.MessageCenter.Number);
1259                                 fprintf(stdout, _("Text: %s\n\n"), message.MessageText); 
1260                                 break;
1261                         default:
1262                                 fprintf(stdout, _("%d. Inbox Message "), message.MessageNumber);
1263                                 if (message.Status)
1264                                         fprintf(stdout, _("(read)\n"));
1265                                 else
1266                                         fprintf(stdout, _("(not read)\n"));
1267                                 fprintf(stdout, _("Date/time: %d/%d/%d %d:%02d:%02d "), \
1268                                         message.Time.Day, message.Time.Month, message.Time.Year, \
1269                                         message.Time.Hour, message.Time.Minute, message.Time.Second);
1270                                 if (message.Time.Timezone) {
1271                                         if (message.Time.Timezone > 0)
1272                                                 fprintf(stdout,_("+%02d00"),message.Time.Timezone);
1273                                         else
1274                                                 fprintf(stdout,_("%02d00"),message.Time.Timezone);
1275                                 }
1276                                 fprintf(stdout, "\n");
1277                                 fprintf(stdout, _("Sender: %s Msg Center: %s\n"), message.Sender, message.MessageCenter.Number);
1278                                 switch (SMS_DetectUDH(&message)) {
1279                                 case GSM_OpLogo:
1280                                         fprintf(stdout, _("GSM operator logo for %s (%s) network.\n"), bitmap.netcode, GSM_GetNetworkName(bitmap.netcode));
1281                                         if (!strcmp(message.Sender, "+998000005") && !strcmp(message.MessageCenter.Number, "+886935074443")) dprintf(_("Saved by Logo Express\n"));
1282                                         if (!strcmp(message.Sender, "+998000002") || !strcmp(message.Sender, "+998000003")) dprintf(_("Saved by Operator Logo Uploader by Thomas Kessler\n"));
1283                                 case GSM_CallerIDLogo:
1284                                         fprintf(stdout, ("Logo:\n"));
1285                                         /* put bitmap into bitmap structure */
1286                                         GSM_ReadSMSBitmap(&message, &bitmap);
1287                                         GSM_PrintBitmap(&bitmap);
1288                                         if (*filename) {
1289                                                 error = GE_NONE;
1290                                                 if ((stat(filename, &buf) == 0)) {
1291                                                         fprintf(stdout, _("File %s exists.\n"), filename);
1292                                                         fprintf(stderr, _("Overwrite? (yes/no) "));
1293                                                         GetLine(stdin, ans, 4);
1294                                                         if (!strcmp(ans, "yes")) {
1295                                                                 error = GSM_SaveBitmapFile(filename, &bitmap);
1296                                                         }
1297                                                 } else error = GSM_SaveBitmapFile(filename, &bitmap);          
1298                                                 if (error!=GE_NONE) fprintf(stderr, _("Couldn't save logofile %s!\n"), filename);
1299                                         }
1300                                         break;
1301                                 case GSM_RingtoneUDH:
1302                                         fprintf(stdout, ("Ringtone\n"));
1303                                         break;
1304                                 case GSM_ConcatenatedMessages:
1305                                         fprintf(stdout, _("Linked (%d/%d):\n"),message.UDH[5],message.UDH[4]);
1306                                 case GSM_NoUDH:
1307                                         fprintf(stdout, _("Text:\n%s\n\n"), message.MessageText);
1308                                         if ((mode != -1) && *filename) {
1309                                                 char buf[1024];
1310                                                 sprintf(buf, "%s%d", filename, count);
1311                                                 mode = GSM_SaveTextFile(buf, message.MessageText, mode);
1312                                         }
1313                                         break;
1314                                 default:
1315                                         fprintf(stderr, _("Unknown\n"));
1316                                         break;
1317                                 }
1318                                 break;
1319                         }
1320                         if (del) {
1321                                 data.SMSMessage = &message;
1322                                 if (GE_NONE != SM_Functions(GOP_DeleteSMS, &data, &State))
1323                                         fprintf(stdout, _("(delete failed)\n"));
1324                                 else
1325                                         fprintf(stdout, _("(message deleted)\n"));
1326                         }
1327                         break;
1328                 case GE_NOTIMPLEMENTED:
1329                         fprintf(stderr, _("Function not implemented in %s model!\n"), model);
1330                         if (GSM && GSM->Terminate) GSM->Terminate();
1331                         return -1;      
1332                 case GE_INVALIDSMSLOCATION:
1333                         fprintf(stderr, _("Invalid location: %s %d\n"), memory_type_string, count);
1334                         break;
1335                 case GE_EMPTYSMSLOCATION:
1336                         fprintf(stderr, _("SMS location %s %d empty.\n"), memory_type_string, count);
1337                         break;
1338                 default:
1339                         fprintf(stdout, _("GetSMS %s %d failed!(%d)\n\n"), memory_type_string, count, error);
1340                         break;
1341                 }
1342         }
1343         
1344         if (GSM && GSM->Terminate) GSM->Terminate();
1345         
1346         return 0;
1347 }
1348
1349 /* Delete SMS messages. */
1350 int deletesms(int argc, char *argv[])
1351 {
1352         GSM_SMSMessage message;
1353         char *memory_type_string;
1354         int start_message, end_message, count;
1355         GSM_Error error;
1356
1357         /* Handle command line args that set type, start and end locations. */
1358         memory_type_string = argv[0];
1359         message.MemoryType = StrToMemoryType(memory_type_string);
1360         if (message.MemoryType == GMT_XX) {
1361                 fprintf(stderr, _("Unknown memory type %s (use ME, SM, ...)!\n"), argv[0]);
1362                 return (-1);
1363         }
1364                 
1365         start_message = end_message = atoi (argv[1]);
1366         if (argc > 2) end_message = atoi (argv[2]);
1367
1368         /* Now delete the requested entries. */
1369         for (count = start_message; count <= end_message; count ++) {
1370
1371                 message.Location = count;
1372                 data.SMSMessage = &message;
1373                 error = SM_Functions(GOP_DeleteSMS, &data, &State);
1374
1375                 if (error == GE_NONE)
1376                         fprintf(stdout, _("Deleted SMS %s %d\n"), memory_type_string, count);
1377                 else {
1378                         if (error == GE_NOTIMPLEMENTED) {
1379                                 fprintf(stderr, _("Function not implemented in %s model!\n"), model);
1380                                 GSM->Terminate();
1381                                 return -1;      
1382                         }
1383                         fprintf(stdout, _("DeleteSMS %s %d failed!(%d)\n\n"), memory_type_string, count, error);
1384                 }
1385         }
1386
1387         GSM->Terminate();
1388
1389         return 0;
1390 }
1391
1392 static volatile bool bshutdown = false;
1393
1394 /* SIGINT signal handler. */
1395 static void interrupted(int sig)
1396 {
1397         signal(sig, SIG_IGN);
1398         bshutdown = true;
1399 }
1400
1401 #ifdef SECURITY
1402
1403 /* In this mode we get the code from the keyboard and send it to the mobile
1404    phone. */
1405 int entersecuritycode(char *type)
1406 {
1407         GSM_Error test;
1408         GSM_SecurityCode SecurityCode;
1409
1410         if (!strcmp(type,"PIN"))
1411                 SecurityCode.Type=GSCT_Pin;
1412         else if (!strcmp(type,"PUK"))
1413                 SecurityCode.Type=GSCT_Puk;
1414         else if (!strcmp(type,"PIN2"))
1415                 SecurityCode.Type=GSCT_Pin2;
1416         else if (!strcmp(type,"PUK2"))
1417                 SecurityCode.Type=GSCT_Puk2;
1418         // FIXME: Entering of SecurityCode does not work :-(
1419         //  else if (!strcmp(type,"SecurityCode"))
1420         //    SecurityCode.Type=GSCT_SecurityCode;
1421         else
1422                 usage();
1423
1424 #ifdef WIN32
1425         printf("Enter your code: ");
1426         gets(SecurityCode.Code);
1427 #else
1428         strcpy(SecurityCode.Code,getpass(_("Enter your code: ")));
1429 #endif
1430
1431         test = GSM->EnterSecurityCode(SecurityCode);
1432         if (test == GE_INVALIDSECURITYCODE)
1433                 fprintf(stdout, _("Error: invalid code.\n"));
1434         else if (test == GE_NONE)
1435                 fprintf(stdout, _("Code ok.\n"));
1436         else if (test == GE_NOTIMPLEMENTED)
1437                 fprintf(stderr, _("Function not implemented in %s model!\n"), model);
1438         else
1439                 fprintf(stdout, _("Other error.\n"));
1440
1441         GSM->Terminate();
1442
1443         return 0;
1444 }
1445
1446 int getsecuritycodestatus(void)
1447 {
1448         int Status;
1449
1450         if (GSM->GetSecurityCodeStatus(&Status) == GE_NONE) {
1451
1452                 fprintf(stdout, _("Security code status: "));
1453
1454                 switch(Status) {
1455                 case GSCT_SecurityCode:
1456                         fprintf(stdout, _("waiting for Security Code.\n"));
1457                         break;
1458                 case GSCT_Pin:
1459                         fprintf(stdout, _("waiting for PIN.\n"));
1460                         break;
1461                 case GSCT_Pin2:
1462                         fprintf(stdout, _("waiting for PIN2.\n"));
1463                         break;
1464                 case GSCT_Puk:
1465                         fprintf(stdout, _("waiting for PUK.\n"));
1466                         break;
1467                 case GSCT_Puk2:
1468                         fprintf(stdout, _("waiting for PUK2.\n"));
1469                         break;
1470                 case GSCT_None:
1471                         fprintf(stdout, _("nothing to enter.\n"));
1472                         break;
1473                 default:
1474                         fprintf(stdout, _("Unknown!\n"));
1475                         break;
1476                 }
1477         }
1478
1479         GSM->Terminate();
1480
1481         return 0;
1482 }
1483
1484
1485 #endif
1486
1487 /* Voice dialing mode. */
1488 int dialvoice(char *Number)
1489 {
1490         GSM->DialVoice(Number);
1491
1492         GSM->Terminate();
1493
1494         return 0;
1495 }
1496
1497 /* The following function allows to send logos using SMS */
1498 int sendlogo(int argc, char *argv[])
1499 {
1500         GSM_SMSMessage SMS;
1501         GSM_Bitmap bitmap;
1502
1503         char Data[sizeof(bitmap.bitmap) +64/*headers safety*/];
1504
1505         int current=0, i;
1506
1507         struct option options[] = {
1508                 SMSC_OPTIONS,
1509                 { NULL,       0,                 NULL, 0}
1510         };
1511
1512         /* Default settings for SMS message:
1513            - no delivery report
1514            - Class Message 1
1515            - no compression
1516            - 8 bit data
1517            - SMSC no. 1
1518            - validity 3 days
1519            - set UserDataHeaderIndicator
1520         */
1521
1522         SMS.Type = GST_MO;
1523         SMS.Class = 1;
1524         SMS.Compression = false;
1525         SMS.EightBit = true;
1526         SMS.MessageCenter.No = 1;
1527         SMS.Validity = 4320; /* 4320 minutes == 72 hours */
1528
1529         optarg = NULL;
1530         optind = 0;
1531         while ((i = getopt_long(argc, argv, "", options, NULL)) != -1) {
1532                 if (smsc_options_parse(i,&SMS))
1533                         continue;
1534                 switch (i) {
1535                 default:
1536                         usage(); /* Would be better to have an sendsms_usage() here. */
1537                 }
1538         }
1539
1540 /*
1541         if (argc!=3 && argc!=4)
1542                 usage();
1543 */
1544
1545         /* The first argument is the type of the logo. */
1546         if (!strcmp(argv[0], "op")) {
1547                 SMS_SetupUDH(&SMS,GSM_OpLogo);          /* error ignored */
1548                 fprintf(stdout, _("Sending operator logo.\n"));
1549         } else if (!strcmp(argv[0], "caller")) {        /* error ignored */
1550                 SMS_SetupUDH(&SMS,GSM_CallerIDLogo);
1551                 fprintf(stdout, _("Sending caller line identification logo.\n"));
1552         } else {
1553                 fprintf(stderr, _("You should specify what kind of logo to send!\n"));
1554                 return (-1);
1555         }
1556
1557         /* The second argument is the destination, ie the phone number of recipient. */
1558         strcpy(SMS.Destination,argv[1]);
1559
1560         /* The third argument is the bitmap file. */
1561         GSM_ReadBitmapFile(argv[2], &bitmap);
1562
1563         /* If we are sending op logo we can rewrite network code. */
1564         if (!strcmp(argv[0], "op")) {
1565                 /*
1566                  * The fourth argument, if present, is the Network code of the operator.
1567                  * Network code is in this format: "xxx yy".
1568                  */
1569                 if (argc > 3) {
1570                         strcpy(bitmap.netcode, argv[3]);
1571 #ifdef DEBUG
1572                         fprintf(stdout, _("Operator code: %s\n"), argv[3]);
1573 #endif
1574                 }
1575
1576                 /* Set the network code */
1577                 Data[current++] = ((bitmap.netcode[1] & 0x0f) << 4) | (bitmap.netcode[0] & 0xf);
1578                 Data[current++] = 0xf0 | (bitmap.netcode[2] & 0x0f);
1579                 Data[current++] = ((bitmap.netcode[5] & 0x0f) << 4) | (bitmap.netcode[4] & 0xf);
1580         }
1581
1582         /* Set the logo size */
1583         Data[current++] = 0x00;         /* RFU by Nokia */
1584         Data[current++] = bitmap.width;
1585         Data[current++] = bitmap.height;
1586
1587         Data[current++] = 0x01;         /* depth=number of grayscales */
1588
1589         memcpy(Data+current,bitmap.bitmap,bitmap.size);
1590         current+=bitmap.size;
1591         
1592         /* Send the message. */
1593         sendsms_deconcatenated(&SMS,Data,current,true/*useudh*/);
1594
1595         GSM->Terminate();
1596         return 0;
1597 }
1598
1599 /* Getting logos. */
1600 GSM_Error SaveBitmapFileOnConsole(char *FileName, GSM_Bitmap *bitmap)
1601 {
1602         int confirm;
1603         char ans[4];
1604         struct stat buf;
1605         GSM_Error error;
1606
1607         /* Ask before overwriting */
1608         while (stat(FileName, &buf) == 0) {
1609                 confirm = 0;
1610                 while (!confirm) {
1611                         fprintf(stderr, _("Saving logo. File \"%s\" exists. (O)verwrite, create (n)ew or (s)kip ? "), FileName);
1612                         GetLine(stdin, ans, 4);
1613                         if (!strcmp(ans, "O") || !strcmp(ans, "o")) confirm = 1;
1614                         if (!strcmp(ans, "N") || !strcmp(ans, "n")) confirm = 2;
1615                         if (!strcmp(ans, "S") || !strcmp(ans, "s")) return GE_USERCANCELED;
1616                 }  
1617                 if (confirm == 1) break;
1618                 if (confirm == 2) {
1619                         fprintf(stderr, _("Enter name of new file: "));
1620                         GetLine(stdin, FileName, 50);
1621                         if (!FileName || (*FileName == 0)) return GE_USERCANCELED;
1622                 }
1623         }
1624   
1625         error = GSM_SaveBitmapFile(FileName, bitmap);
1626   
1627         switch (error) {
1628         case GE_CANTOPENFILE:
1629                 fprintf(stderr, _("Failed to write file \"%s\"\n"), FileName);
1630                 break;
1631         default:
1632                 break;
1633         }
1634   
1635         return error;
1636 }
1637
1638 int getlogo(int argc, char *argv[])
1639 {
1640         GSM_Bitmap bitmap;
1641         GSM_Error error;
1642         GSM_Statemachine *sm = &State;
1643
1644         bitmap.type=GSM_None;
1645
1646         if (!strcmp(argv[0], "op"))
1647                 bitmap.type = GSM_OperatorLogo;
1648     
1649         if (!strcmp(argv[0], "caller")) {
1650                 /* There is caller group number missing in argument list. */
1651                 if (argc == 3) {     
1652                         bitmap.number=argv[2][0]-'0';
1653                         if ((bitmap.number < 0) || (bitmap.number > 9)) bitmap.number = 0;
1654                 } else {
1655                         bitmap.number = 0;
1656                 }
1657                 bitmap.type = GSM_CallerLogo;
1658         }
1659     
1660         if (!strcmp(argv[0],"startup"))
1661                 bitmap.type = GSM_StartupLogo;
1662         else if (!strcmp(argv[0], "dealer"))
1663                 bitmap.type = GSM_DealerNoteText;  
1664         else if (!strcmp(argv[0], "text"))
1665                 bitmap.type=GSM_WelcomeNoteText;  
1666
1667         if (bitmap.type != GSM_None) {
1668     
1669                 fprintf(stdout, _("Getting Logo\n"));
1670         
1671                 data.Bitmap=&bitmap;
1672                 error=SM_Functions(GOP_GetBitmap, &data, sm);
1673  
1674                 switch (error) {
1675                 case GE_NONE:
1676                         if (bitmap.type == GSM_DealerNoteText) fprintf(stdout, _("Dealer welcome note "));
1677                         if (bitmap.type == GSM_WelcomeNoteText) fprintf(stdout, _("Welcome note "));    
1678                         if (bitmap.type == GSM_DealerNoteText || bitmap.type==GSM_WelcomeNoteText) {
1679                                 if (bitmap.text[0]) {
1680                                         fprintf(stdout, _("currently set to \"%s\"\n"), bitmap.text);
1681                                 } else {
1682                                         fprintf(stdout, _("currently empty\n"));
1683                                 }
1684                         } else {
1685                                 if (bitmap.width) {
1686                                         switch (bitmap.type) {
1687                                         case GSM_OperatorLogo:
1688                                                 fprintf(stdout,"Operator logo for %s (%s) network got succesfully\n",bitmap.netcode,GSM_GetNetworkName(bitmap.netcode));
1689                                                 if (argc==3) {
1690                                                         strncpy(bitmap.netcode,argv[2], 7);
1691                                                         if (!strcmp(GSM_GetNetworkName(bitmap.netcode), "unknown")) {
1692                                                                 fprintf(stderr, "Sorry, gnokii doesn't know %s network !\n", bitmap.netcode);
1693                                                                 return -1;
1694                                                         }
1695                                                 }
1696                                                 break;
1697                                         case GSM_StartupLogo:
1698                                                 fprintf(stdout, "Startup logo got successfully\n");
1699                                                 if (argc == 3) {
1700                                                         strncpy(bitmap.netcode,argv[2], 7);
1701                                                         if (!strcmp(GSM_GetNetworkName(bitmap.netcode), "unknown")) {
1702                                                                 fprintf(stderr, "Sorry, gnokii doesn't know %s network !\n", bitmap.netcode);
1703                                                                 return -1;
1704                                                         }
1705                                                 }
1706                                                 break;
1707                                         case GSM_CallerLogo:
1708                                                 fprintf(stdout,"Caller logo got successfully\n");
1709                                                 if (argc == 4) {
1710                                                         strncpy(bitmap.netcode,argv[3],7);
1711                                                         if (!strcmp(GSM_GetNetworkName(bitmap.netcode), "unknown")) {
1712                                                                 fprintf(stderr, "Sorry, gnokii doesn't know %s network !\n", bitmap.netcode);
1713                                                                 return -1;
1714                                                         }
1715                                                 }
1716                                                 break;
1717                                         default:
1718                                                 fprintf(stdout,"Unknown bitmap type.\n");
1719                                                 break;
1720                                         }
1721                                         if (argc > 1) {
1722                                                 if (SaveBitmapFileOnConsole(argv[1], &bitmap) != GE_NONE) return (-1);
1723                                         }
1724                                 } else {
1725                                         fprintf(stdout,"Your phone doesn't have logo uploaded !\n");
1726                                         return -1;
1727                                 }
1728                         }
1729                         break;
1730                 case GE_NOTIMPLEMENTED:
1731                         fprintf(stderr, _("Function not implemented !\n"));
1732                         return -1;
1733                 case GE_NOTSUPPORTED:
1734                         fprintf(stderr, _("This kind of logo is not supported !\n"));
1735                         return -1;
1736                 default:
1737                         fprintf(stderr, _("Error getting logo !\n"));
1738                         return -1;
1739                 }
1740         } else {
1741                 fprintf(stderr, _("What kind of logo do you want to get ?\n"));
1742                 return -1;
1743         }
1744
1745         return 0;
1746 }
1747
1748
1749 /* Sending logos. */
1750 GSM_Error ReadBitmapFileOnConsole(char *FileName, GSM_Bitmap *bitmap)
1751 {
1752         GSM_Error error;
1753   
1754         error = GSM_ReadBitmapFile(FileName, bitmap);
1755   
1756         switch (error) {
1757         case GE_CANTOPENFILE:
1758                 fprintf(stderr, _("Failed to read file \"%s\"\n"), FileName);
1759                 break;
1760         case GE_WRONGNUMBEROFCOLORS:
1761                 fprintf(stderr, _("Wrong number of colors in \"%s\" logofile (accepted only 2-colors files) !\n"), FileName);
1762                 break;
1763         case GE_WRONGCOLORS:
1764                 fprintf(stderr, _("Wrong colors in \"%s\" logofile !\n"), FileName);
1765                 break;
1766         case GE_INVALIDFILEFORMAT:
1767                 fprintf(stderr, _("Invalid format of \"%s\" logofile !\n"), FileName);
1768                 break;
1769         case GE_SUBFORMATNOTSUPPORTED:
1770                 fprintf(stderr, _("Sorry, gnokii doesn't support used subformat in file \"%s\" !\n"), FileName);
1771                 break;
1772         case GE_FILETOOSHORT:
1773                 fprintf(stderr, _("\"%s\" logofile is too short !\n"), FileName);
1774                 break;  
1775         case GE_INVALIDIMAGESIZE:
1776                 fprintf(stderr, _("Bitmap size doesn't supported by fileformat or different from 72x14, 84x48 and 72x28 !\n"));
1777                 break;
1778         default:
1779                 break;
1780         }
1781   
1782         return error;
1783 }
1784
1785
1786 int setlogo(int argc, char *argv[])
1787 {
1788         GSM_Bitmap bitmap,oldbit;
1789         GSM_NetworkInfo NetworkInfo;
1790         GSM_Error error;
1791   
1792         bool ok = true;
1793         int i;
1794   
1795         if (!strcmp(argv[0],"text") || !strcmp(argv[0],"dealer")) {
1796                 if (!strcmp(argv[0], "text")) bitmap.type = GSM_WelcomeNoteText;
1797                 else bitmap.type = GSM_DealerNoteText;
1798                 bitmap.text[0] = 0x00;
1799                 if (argc > 1) strncpy(bitmap.text, argv[1], 255);
1800         } else {
1801                 if (!strcmp(argv[0], "op") || !strcmp(argv[0], "startup") || !strcmp(argv[0], "caller")) {
1802                         if (argc > 1) {
1803                                 if (ReadBitmapFileOnConsole(argv[1], &bitmap) != GE_NONE) {
1804                                         GSM->Terminate();
1805                                         return(-1);
1806                                 }
1807
1808                                 if (!strcmp(argv[0], "op")) {
1809                                         if (bitmap.type != GSM_OperatorLogo || argc < 3) {
1810                                                 if (GSM->GetNetworkInfo(&NetworkInfo) == GE_NONE) strncpy(bitmap.netcode, NetworkInfo.NetworkCode, 7);
1811                                         }
1812                                         GSM_ResizeBitmap(&bitmap, GSM_OperatorLogo, GSM_Info);
1813                                         if (argc == 3) {
1814                                                 strncpy(bitmap.netcode, argv[2], 7);
1815                                                 if (!strcmp(GSM_GetNetworkName(bitmap.netcode), "unknown")) {
1816                                                         fprintf(stderr, "Sorry, gnokii doesn't know %s network !\n", bitmap.netcode);
1817                                                         return -1;
1818                                                 }
1819                                         }
1820                                 }
1821                                 if (!strcmp(argv[0], "startup")) {
1822                                         GSM_ResizeBitmap(&bitmap, GSM_StartupLogo, GSM_Info);
1823                                 }
1824                                 if (!strcmp(argv[0],"caller")) {
1825                                         GSM_ResizeBitmap(&bitmap, GSM_CallerLogo, GSM_Info);
1826                                         if (argc > 2) {
1827                                                 bitmap.number = argv[2][0] - '0';
1828                                                 if ((bitmap.number < 0) || (bitmap.number > 9)) bitmap.number = 0;
1829                                         } else {
1830                                                 bitmap.number = 0;
1831                                         }
1832                                         oldbit.type = GSM_CallerLogo;
1833                                         oldbit.number = bitmap.number;
1834                                         if (GSM->GetBitmap(&oldbit) == GE_NONE) {
1835                                                 /* We have to get the old name and ringtone!! */
1836                                                 bitmap.ringtone = oldbit.ringtone;
1837                                                 strncpy(bitmap.text, oldbit.text, 255);
1838                                         }
1839                                         if (argc > 3) strncpy(bitmap.text, argv[3], 255);         
1840                                 }
1841                                 fprintf(stdout, _("Setting Logo.\n"));
1842                         } else {
1843                                 /* FIX ME: is it possible to permanently remove op logo ? */
1844                                 if (!strcmp(argv[0], "op"))
1845                                 {
1846                                         bitmap.type = GSM_OperatorLogo;
1847                                         strncpy(bitmap.netcode, "000 00", 7);
1848                                         bitmap.width = 72;
1849                                         bitmap.height = 14;
1850                                         bitmap.size = bitmap.width * bitmap.height / 8;
1851                                         GSM_ClearBitmap(&bitmap);
1852                                 }
1853                                 /* FIX ME: how to remove startup and group logos ? */
1854                                 fprintf(stdout, _("Removing Logo.\n"));
1855                         }  
1856                 } else {
1857                         fprintf(stderr, _("What kind of logo do you want to set ?\n"));
1858                         GSM->Terminate();
1859                         return -1;
1860                 }
1861         }
1862     
1863         error=GSM->SetBitmap(&bitmap);
1864   
1865         switch (error) {
1866         case GE_NONE:
1867                 oldbit.type = bitmap.type;
1868                 oldbit.number = bitmap.number;
1869                 if (GSM->GetBitmap(&oldbit) == GE_NONE) {
1870                         if (bitmap.type == GSM_WelcomeNoteText ||
1871                             bitmap.type == GSM_DealerNoteText) {
1872                                 if (strcmp(bitmap.text, oldbit.text)) {
1873                                         fprintf(stderr, _("Error setting"));
1874                                         if (bitmap.type == GSM_DealerNoteText) fprintf(stderr, _(" dealer"));
1875                                         fprintf(stderr, _(" welcome note - "));
1876
1877                                         /* I know, it looks horrible, but... */
1878                                         /* I set it to the short string - if it won't be set */
1879                                         /* it means, PIN is required. If it will be correct, previous */
1880                                         /* (user) text was too long */
1881
1882                                         /* Without it, I could have such thing: */
1883                                         /* user set text to very short string (for example, "Marcin") */
1884                                         /* then enable phone without PIN and try to set it to the very long (too long for phone) */
1885                                         /* string (which start with "Marcin"). If we compare them as only length different, we could think, */
1886                                         /* that phone accepts strings 6 chars length only (length of "Marcin") */
1887                                         /* When we make it correct, we don't have this mistake */
1888                         
1889                                         strcpy(oldbit.text, "!\0");
1890                                         GSM->SetBitmap(&oldbit);
1891                                         GSM->GetBitmap(&oldbit);
1892                                         if (oldbit.text[0]!='!') {
1893                                                 fprintf(stderr, _("SIM card and PIN is required\n"));
1894                                         } else {
1895                                                 GSM->SetBitmap(&bitmap);
1896                                                 GSM->GetBitmap(&oldbit);
1897                                                 fprintf(stderr, _("too long, truncated to \"%s\" (length %i)\n"),oldbit.text,strlen(oldbit.text));
1898                                         }
1899                                         ok = false;
1900                                 }
1901                         } else {
1902                                 if (bitmap.type == GSM_StartupLogo) {
1903                                         for (i = 0; i < oldbit.size; i++) {
1904                                                 if (oldbit.bitmap[i] != bitmap.bitmap[i]) {
1905                                                         fprintf(stderr, _("Error setting startup logo - SIM card and PIN is required\n"));
1906                                                         ok = false;
1907                                                         break;
1908                                                 }
1909                                         }
1910                                 }
1911                         }
1912                 }
1913                 if (ok) fprintf(stdout, _("Done.\n"));
1914                 break;
1915         case GE_NOTIMPLEMENTED:
1916                 fprintf(stderr, _("Function not implemented.\n"));
1917                 break;
1918         case GE_NOTSUPPORTED:
1919                 fprintf(stderr, _("This kind of logo is not supported.\n"));
1920                 break;
1921         default:
1922                 fprintf(stderr, _("Error !\n"));
1923                 break;
1924         }
1925   
1926         GSM->Terminate();
1927
1928         return 0;
1929 }
1930
1931
1932 int viewlogo(char *filename)
1933 {
1934         GSM_Error error;
1935
1936         error = GSM_ShowBitmapFile(filename);
1937         return 0;
1938 }
1939
1940 /* Calendar notes receiving. */
1941 int getcalendarnote(int argc, char *argv[])
1942 {
1943         GSM_CalendarNote        CalendarNote;
1944         GSM_Data                data;
1945         GSM_Error               error = GE_NONE;
1946         int                     i, first_location, last_location;
1947         bool                    vCal = false;
1948         
1949         struct option options[] = {
1950                 { "vCard",    optional_argument, NULL, '1'},
1951                 { NULL,      0,                 NULL, 0}
1952         };
1953         
1954         optarg = NULL;
1955         optind = 0;
1956
1957         first_location = last_location = atoi(argv[0]);
1958         if ((argc > 1) && (argv[1][0] != '-')) {
1959                 last_location = atoi(argv[1]);
1960         }
1961         
1962         while ((i = getopt_long(argc, argv, "v", options, NULL)) != -1) {
1963                 switch (i) {       
1964                 case 'v':
1965                         vCal=true;
1966                         break;
1967                 default:
1968                         usage(); /* Would be better to have an calendar_usage() here. */
1969                         return -1;
1970                 }
1971         }
1972
1973                                                                                                         
1974         for (i = first_location; i <= last_location; i++) {
1975                 CalendarNote.Location = i;
1976                 if (GSM && GSM->GetCalendarNote && GSM->Terminate) {
1977                         error = GSM->GetCalendarNote(&CalendarNote);
1978                         GSM->Terminate();
1979                 } else {
1980                         GSM_DataClear(&data);
1981                         data.CalendarNote = &CalendarNote;
1982
1983                         error = SM_Functions(GOP_GetCalendarNote, &data, &State);
1984                 }
1985                 switch (error) {
1986                 case GE_NONE:
1987                         if (vCal) {
1988                                 fprintf(stdout, "BEGIN:VCALENDAR\n");
1989                                 fprintf(stdout, "VERSION:1.0\n");
1990                                 fprintf(stdout, "BEGIN:VEVENT\n");
1991                                 fprintf(stdout, "CATEGORIES:");
1992                                 switch (CalendarNote.Type) {
1993                                 case GCN_REMINDER:
1994                                         fprintf(stdout, "MISCELLANEOUS\n");
1995                                         break;
1996                                 case GCN_CALL:
1997                                         fprintf(stdout, "PHONE CALL\n");
1998                                         break;
1999                                 case GCN_MEETING:
2000                                         fprintf(stdout, "MEETING\n");
2001                                         break;
2002                                 case GCN_BIRTHDAY:
2003                                         fprintf(stdout, "SPECIAL OCCASION\n");
2004                                         break;
2005                                 default:
2006                                         fprintf(stdout, "UNKNOWN\n");
2007                                         break;
2008                                 }
2009                                 fprintf(stdout, "SUMMARY:%s\n",CalendarNote.Text);
2010                                 fprintf(stdout, "DTSTART:%04d%02d%02dT%02d%02d%02d\n", CalendarNote.Time.Year,
2011                                         CalendarNote.Time.Month, CalendarNote.Time.Day, CalendarNote.Time.Hour,
2012                                         CalendarNote.Time.Minute, CalendarNote.Time.Second);
2013                                 if (CalendarNote.Alarm.Year!=0) {
2014                                         fprintf(stdout, "DALARM:%04d%02d%02dT%02d%02d%02d\n", CalendarNote.Alarm.Year,
2015                                                 CalendarNote.Alarm.Month, CalendarNote.Alarm.Day, CalendarNote.Alarm.Hour,
2016                                                 CalendarNote.Alarm.Minute, CalendarNote.Alarm.Second);
2017                                 }
2018                                 fprintf(stdout, "END:VEVENT\n");
2019                                 fprintf(stdout, "END:VCALENDAR\n");
2020
2021                         } else {  /* not vCal */
2022                                 fprintf(stdout, _("   Type of the note: "));
2023
2024                                 switch (CalendarNote.Type) {
2025                                 case GCN_REMINDER:
2026                                         fprintf(stdout, _("Reminder\n"));
2027                                         break;
2028                                 case GCN_CALL:
2029                                         fprintf(stdout, _("Call\n"));
2030                                         break;
2031                                 case GCN_MEETING:
2032                                         fprintf(stdout, _("Meeting\n"));
2033                                         break;
2034                                 case GCN_BIRTHDAY:
2035                                         fprintf(stdout, _("Birthday\n"));
2036                                         break;
2037                                 default:
2038                                         fprintf(stdout, _("Unknown\n"));
2039                                         break;
2040                                 }
2041
2042                                 fprintf(stdout, _("   Date: %d-%02d-%02d\n"), CalendarNote.Time.Year,
2043                                         CalendarNote.Time.Month,
2044                                         CalendarNote.Time.Day);
2045
2046                                 fprintf(stdout, _("   Time: %02d:%02d:%02d\n"), CalendarNote.Time.Hour,
2047                                         CalendarNote.Time.Minute,
2048                                         CalendarNote.Time.Second);
2049
2050                                 if (CalendarNote.Alarm.AlarmEnabled == 1) {
2051                                         fprintf(stdout, _("   Alarm date: %d-%02d-%02d\n"), CalendarNote.Alarm.Year,
2052                                                 CalendarNote.Alarm.Month,
2053                                                 CalendarNote.Alarm.Day);
2054
2055                                         fprintf(stdout, _("   Alarm time: %02d:%02d:%02d\n"), CalendarNote.Alarm.Hour,
2056                                                 CalendarNote.Alarm.Minute,
2057                                                 CalendarNote.Alarm.Second);
2058                                 }
2059
2060                                 fprintf(stdout, _("   Text: %s\n"), CalendarNote.Text);
2061
2062                                 if (CalendarNote.Type == GCN_CALL)
2063                                         fprintf(stdout, _("   Phone: %s\n"), CalendarNote.Phone);
2064                         }
2065                         break;
2066                 case GE_NOTIMPLEMENTED:
2067                         fprintf(stderr, _("Function not implemented.\n"));
2068                         break;
2069                 default:
2070                         fprintf(stderr, _("The calendar note can not be read\n"));
2071                         break;
2072                 }
2073         }
2074         
2075         GSM->Terminate();
2076         return error;
2077 }
2078
2079 /* Writing calendar notes. */
2080 int writecalendarnote(char *argv[])
2081 {
2082         GSM_CalendarNote CalendarNote;
2083
2084         if (GSM_ReadVCalendarFile(argv[0], &CalendarNote, atoi(argv[1]))) {
2085                 fprintf(stdout, _("Failed to load vCalendar file.\n"));
2086                 return(-1);
2087         }
2088
2089         /* Error 22=Calendar full ;-) */
2090         if ((GSM->WriteCalendarNote(&CalendarNote)) == GE_NONE)
2091                 fprintf(stdout, _("Succesfully written!\n"));
2092         else
2093                 fprintf(stdout, _("Failed to write calendar note!\n"));
2094
2095         GSM->Terminate();
2096
2097         return 0;
2098 }
2099
2100 /* Calendar note deleting. */
2101 int deletecalendarnote(int argc, char *argv[])
2102 {
2103         GSM_CalendarNote CalendarNote;
2104         int i, first_location, last_location;
2105
2106         first_location = last_location = atoi(argv[0]);
2107         if (argc > 1) last_location = atoi(argv[1]);
2108         
2109         for (i = first_location; i <= last_location; i++) {
2110
2111                 CalendarNote.Location = i;
2112
2113                 if (GSM->DeleteCalendarNote(&CalendarNote) == GE_NONE) {
2114                         fprintf(stdout, _("   Calendar note deleted.\n"));
2115                 } else {
2116                         fprintf(stderr, _("The calendar note can not be deleted\n"));
2117                 }
2118
2119         }
2120
2121         GSM->Terminate();
2122
2123         return 0;
2124 }
2125
2126 /* Setting the date and time. */
2127 int setdatetime(int argc, char *argv[])
2128 {
2129         struct tm *now;
2130         time_t nowh;
2131         GSM_DateTime Date;
2132
2133         nowh = time(NULL);
2134         now = localtime(&nowh);
2135
2136         Date.Year = now->tm_year;
2137         Date.Month = now->tm_mon+1;
2138         Date.Day = now->tm_mday;
2139         Date.Hour = now->tm_hour;
2140         Date.Minute = now->tm_min;
2141         Date.Second = now->tm_sec;
2142
2143         if (argc > 0) Date.Year = atoi (argv[0]);
2144         if (argc > 1) Date.Month = atoi (argv[1]);
2145         if (argc > 2) Date.Day = atoi (argv[2]);
2146         if (argc > 3) Date.Hour = atoi (argv[3]);
2147         if (argc > 4) Date.Minute = atoi (argv[4]);
2148
2149         if (Date.Year < 1900) {
2150
2151                 /* Well, this thing is copyrighted in U.S. This technique is known as
2152                    Windowing and you can read something about it in LinuxWeekly News:
2153                    http://lwn.net/1999/features/Windowing.phtml. This thing is beeing
2154                    written in Czech republic and Poland where algorithms are not allowed
2155                    to be patented. */
2156
2157                 if (Date.Year > 90)
2158                         Date.Year = Date.Year + 1900;
2159                 else
2160                         Date.Year = Date.Year + 2000;
2161         }
2162
2163         /* FIXME: Error checking should be here. */
2164         GSM->SetDateTime(&Date);
2165
2166         GSM->Terminate();
2167
2168         return 0;
2169 }
2170
2171 /* In this mode we receive the date and time from mobile phone. */
2172 int getdatetime(void) {
2173         GSM_Data        data;
2174         GSM_DateTime    date_time;
2175         GSM_Error       error;
2176         
2177         if (GSM && GSM->GetDateTime && GSM->Terminate) {
2178                 error = GSM->GetDateTime(&date_time);
2179                 GSM->Terminate();
2180         } else {
2181                 GSM_DataClear(&data);
2182                 data.DateTime = &date_time;
2183                 
2184                 error = SM_Functions(GOP_GetDateTime, &data, &State);
2185         }
2186         
2187         switch (error) {
2188         case GE_NONE:
2189                 fprintf(stdout, _("Date: %4d/%02d/%02d\n"), date_time.Year, date_time.Month, date_time.Day);
2190                 fprintf(stdout, _("Time: %02d:%02d:%02d\n"), date_time.Hour, date_time.Minute, date_time.Second);
2191                 break;
2192         case GE_NOTIMPLEMENTED:
2193                 fprintf(stdout, _("Function not implemented in %s !\n"), model);
2194                 break;
2195         default:
2196                 fprintf(stdout, _("Internal error\n"));
2197                 break;
2198         }
2199         
2200         return error;
2201 }
2202
2203 /* Setting the alarm. */
2204 int setalarm(char *argv[])
2205 {
2206         GSM_DateTime Date;
2207
2208         Date.Hour = atoi(argv[0]);
2209         Date.Minute = atoi(argv[1]);
2210
2211         GSM->SetAlarm(1, &Date);
2212
2213         GSM->Terminate();
2214
2215         return 0;
2216 }
2217
2218 /* Getting the alarm. */
2219 int getalarm(void)
2220 {
2221         GSM_Error       error;
2222         GSM_Data        data;
2223         GSM_DateTime    date_time;
2224         
2225         if (GSM && GSM->GetAlarm && GSM->Terminate) {
2226                 error = GSM->GetAlarm(0, &date_time);
2227                 GSM->Terminate();
2228         } else {
2229                 GSM_DataClear(&data);
2230                 data.DateTime = &date_time;
2231                 
2232                 error = SM_Functions(GOP_GetAlarm, &data, &State);
2233         }
2234         
2235         switch (error) {
2236         case GE_NONE:
2237                 fprintf(stdout, _("Alarm: %s\n"), (date_time.AlarmEnabled==0)?"off":"on");
2238                 fprintf(stdout, _("Time: %02d:%02d\n"), date_time.Hour, date_time.Minute);
2239                 break;
2240         case GE_NOTIMPLEMENTED:
2241                 fprintf(stdout, _("Function not implemented in %s !\n"), model);
2242                 break;
2243         default:
2244                 fprintf(stdout, _("Internal error\n"));
2245                 break;
2246         }
2247         
2248         return error;
2249 }
2250
2251 /* In monitor mode we don't do much, we just initialise the fbus code.
2252    Note that the fbus code no longer has an internal monitor mode switch,
2253    instead compile with DEBUG enabled to get all the gumpf. */
2254 int monitormode(void)
2255 {
2256         float rflevel = -1, batterylevel = -1;
2257 //      GSM_PowerSource powersource = -1;
2258         GSM_RFUnits rf_units = GRF_Arbitrary;
2259         GSM_BatteryUnits batt_units = GBU_Arbitrary;
2260         GSM_Statemachine *sm = &State;
2261         GSM_Data data;
2262
2263 //      GSM_NetworkInfo NetworkInfo;
2264 //      GSM_CBMessage CBMessage;
2265
2266         GSM_MemoryStatus SIMMemoryStatus   = {GMT_SM, 0, 0};
2267         GSM_MemoryStatus PhoneMemoryStatus = {GMT_ME, 0, 0};
2268         GSM_MemoryStatus DC_MemoryStatus   = {GMT_DC, 0, 0};
2269         GSM_MemoryStatus EN_MemoryStatus   = {GMT_EN, 0, 0};
2270         GSM_MemoryStatus FD_MemoryStatus   = {GMT_FD, 0, 0};
2271         GSM_MemoryStatus LD_MemoryStatus   = {GMT_LD, 0, 0};
2272         GSM_MemoryStatus MC_MemoryStatus   = {GMT_MC, 0, 0};
2273         GSM_MemoryStatus ON_MemoryStatus   = {GMT_ON, 0, 0};
2274         GSM_MemoryStatus RC_MemoryStatus   = {GMT_RC, 0, 0};
2275
2276 //      GSM_SMSStatus SMSStatus = {0, 0};
2277
2278 //      char Number[20];
2279         
2280         GSM_DataClear(&data);
2281
2282         /* We do not want to monitor serial line forever - press Ctrl+C to stop the
2283            monitoring mode. */
2284         signal(SIGINT, interrupted);
2285
2286         fprintf (stderr, _("Entering monitor mode...\n"));
2287
2288         //sleep(1);
2289         //GSM->EnableCellBroadcast();
2290
2291         /* Loop here indefinitely - allows you to see messages from GSM code in
2292            response to unknown messages etc. The loops ends after pressing the
2293            Ctrl+C. */
2294         data.RFUnits=&rf_units;
2295         data.RFLevel=&rflevel;
2296         data.BatteryUnits=&batt_units;
2297         data.BatteryLevel=&batterylevel;
2298
2299         while (!bshutdown) {
2300                 if (SM_Functions(GOP_GetRFLevel,&data,sm) == GE_NONE)
2301                         fprintf(stdout, _("RFLevel: %d\n"), (int)rflevel);
2302
2303                 if (SM_Functions(GOP_GetBatteryLevel,&data,sm) == GE_NONE)
2304                         fprintf(stdout, _("Battery: %d\n"), (int)batterylevel);
2305
2306 //              if (GSM->GetPowerSource(&powersource) == GE_NONE)
2307 //                      fprintf(stdout, _("Power Source: %s\n"), (powersource==GPS_ACDC)?_("AC/DC"):_("battery"));
2308
2309                 data.MemoryStatus=&SIMMemoryStatus;
2310                 if (SM_Functions(GOP_GetMemoryStatus,&data,sm) == GE_NONE)
2311                         fprintf(stdout, _("SIM: Used %d, Free %d\n"), SIMMemoryStatus.Used, SIMMemoryStatus.Free);
2312
2313                 data.MemoryStatus=&PhoneMemoryStatus;
2314                 if (SM_Functions(GOP_GetMemoryStatus,&data,sm) == GE_NONE)
2315                         fprintf(stdout, _("Phone: Used %d, Free %d\n"), PhoneMemoryStatus.Used, PhoneMemoryStatus.Free);
2316
2317                 data.MemoryStatus=&DC_MemoryStatus;
2318                 if (SM_Functions(GOP_GetMemoryStatus,&data,sm) == GE_NONE)
2319                         fprintf(stdout, _("DC: Used %d, Free %d\n"), DC_MemoryStatus.Used, DC_MemoryStatus.Free);
2320
2321                 data.MemoryStatus=&EN_MemoryStatus;
2322                 if (SM_Functions(GOP_GetMemoryStatus,&data,sm) == GE_NONE)
2323                         fprintf(stdout, _("EN: Used %d, Free %d\n"), EN_MemoryStatus.Used, EN_MemoryStatus.Free);
2324
2325                 data.MemoryStatus=&FD_MemoryStatus;
2326                 if (SM_Functions(GOP_GetMemoryStatus,&data,sm) == GE_NONE)
2327                         fprintf(stdout, _("FD: Used %d, Free %d\n"), FD_MemoryStatus.Used, FD_MemoryStatus.Free);
2328
2329                 data.MemoryStatus=&LD_MemoryStatus;
2330                 if (SM_Functions(GOP_GetMemoryStatus,&data,sm) == GE_NONE)
2331                         fprintf(stdout, _("LD: Used %d, Free %d\n"), LD_MemoryStatus.Used, LD_MemoryStatus.Free);
2332
2333                 data.MemoryStatus=&MC_MemoryStatus;
2334                 if (SM_Functions(GOP_GetMemoryStatus,&data,sm) == GE_NONE)
2335                         fprintf(stdout, _("MC: Used %d, Free %d\n"), MC_MemoryStatus.Used, MC_MemoryStatus.Free);
2336
2337                 data.MemoryStatus=&ON_MemoryStatus;
2338                 if (SM_Functions(GOP_GetMemoryStatus,&data,sm) == GE_NONE)
2339                         fprintf(stdout, _("ON: Used %d, Free %d\n"), ON_MemoryStatus.Used, ON_MemoryStatus.Free);
2340
2341                 data.MemoryStatus=&RC_MemoryStatus;
2342                 if (SM_Functions(GOP_GetMemoryStatus,&data,sm) == GE_NONE)
2343                         fprintf(stdout, _("RC: Used %d, Free %d\n"), RC_MemoryStatus.Used, RC_MemoryStatus.Free);
2344
2345 //              if (GSM->GetSMSStatus(&SMSStatus) == GE_NONE)
2346 //                      fprintf(stdout, _("SMS Messages: UnRead %d, Number %d\n"), SMSStatus.UnRead, SMSStatus.Number);
2347
2348 //              if (GSM->GetIncomingCallNr(Number) == GE_NONE)
2349 //                      fprintf(stdout, _("Incoming call: %s\n"), Number);
2350
2351 //              if (GSM->GetNetworkInfo(&NetworkInfo) == GE_NONE)
2352 //                      fprintf(stdout, _("Network: %s (%s), LAC: %s, CellID: %s\n"), GSM_GetNetworkName (NetworkInfo.NetworkCode), GSM_GetCountryName(NetworkInfo.NetworkCode), NetworkInfo.LAC, NetworkInfo.CellID);
2353
2354 //              if (GSM->ReadCellBroadcast(&CBMessage) == GE_NONE)
2355 //                      fprintf(stdout, _("Cell broadcast received on channel %d: %s\n"), CBMessage.Channel, CBMessage.Message);
2356             
2357                 sleep(1);
2358         }
2359
2360         fprintf (stderr, _("Leaving monitor mode...\n"));
2361
2362         //GSM->Terminate();
2363
2364         return 0;
2365 }
2366
2367
2368 #define ESC "\e"
2369
2370 static GSM_Error PrettyOutputFn(char *Display, char *Indicators)
2371 {
2372         if (Display)
2373                 printf(ESC "[10;0H Display is:\n%s\n", Display);
2374         if (Indicators)
2375                 printf(ESC "[9;0H Indicators: %s                                                    \n", Indicators);
2376         printf(ESC "[1;1H");
2377         return GE_NONE;
2378 }
2379
2380 #if 0
2381 // Uncomment it if used
2382 static GSM_Error OutputFn(char *Display, char *Indicators)
2383 {
2384         if (Display)
2385                 printf("New display is:\n%s\n", Display);
2386         if (Indicators)
2387                 printf("Indicators: %s\n", Indicators);
2388         return GE_NONE;
2389 }
2390 #endif
2391
2392 void console_raw(void)
2393 {
2394 #ifndef WIN32
2395         struct termios it;
2396
2397         tcgetattr(fileno(stdin), &it);
2398         it.c_lflag &= ~(ICANON);
2399         //it.c_iflag &= ~(INPCK|ISTRIP|IXON);
2400         it.c_cc[VMIN] = 1;
2401         it.c_cc[VTIME] = 0;
2402
2403         tcsetattr(fileno(stdin), TCSANOW, &it);
2404 #endif
2405 }
2406
2407 int displayoutput(void)
2408 {
2409         GSM_Data data;
2410         GSM_Statemachine *sm = &State;
2411         GSM_Error error;
2412
2413         data.OutputFn = PrettyOutputFn;
2414
2415         error = SM_Functions(GOP_DisplayOutput, &data, sm);
2416         console_raw();
2417         fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
2418
2419         if (error == GE_NONE) {
2420
2421                 /* We do not want to see texts forever - press Ctrl+C to stop. */
2422                 signal(SIGINT, interrupted);    
2423
2424                 fprintf (stderr, _("Entered display monitoring mode...\n"));
2425                 fprintf (stderr, ESC "c" );
2426
2427                 /* Loop here indefinitely - allows you to read texts from phone's
2428                    display. The loops ends after pressing the Ctrl+C. */
2429                 while (!bshutdown) {
2430                         char buf[105];
2431                         memset(&buf[0], 0, 102);
2432                         while (read(0, buf, 100) > 0) {
2433                                 fprintf(stderr, "handling keys (%d).\n", strlen(buf));
2434                                 if (GSM->HandleString(buf) != GE_NONE)
2435                                         fprintf(stdout, _("Key press simulation failed.\n"));
2436                                 memset(buf, 0, 102);
2437                         }
2438                         SM_Loop(sm, 1);
2439                 }
2440                 fprintf (stderr, "Shutting down\n");
2441
2442                 fprintf (stderr, _("Leaving display monitor mode...\n"));
2443                 data.OutputFn = NULL;
2444
2445                 error = SM_Functions(GOP_DisplayOutput, &data, sm);
2446                 if (error != GE_NONE)
2447                         fprintf (stderr, _("Error!\n"));
2448         } else
2449                 fprintf (stderr, _("Error!\n"));
2450
2451         GSM->Terminate();
2452         return 0;
2453 }
2454
2455 /* Reads profile from phone and displays its' settings */
2456 int getprofile(int argc, char *argv[])
2457 {
2458         int max_profiles;
2459         int start, stop, i;
2460         GSM_Profile profile;
2461         GSM_Error error;
2462   
2463         /* Hopefully is 64 larger as FB38_MAX* / FB61_MAX* */
2464         char model[64];
2465
2466         profile.Number = 0;
2467         error = GSM->GetProfile(&profile);
2468
2469         if (error == GE_NONE) {
2470   
2471                 while (GSM->GetModel(model) != GE_NONE)
2472                         sleep(1);
2473
2474                 max_profiles = 7; /* This is correct for 6110 (at least my). How do we get
2475                                      the number of profiles? */
2476
2477                 /*For N5110*/
2478                 /*FIX ME: It should be set to 3 for N5130 and 3210 too*/
2479                 if (!strcmp(model, "NSE-1"))
2480                         max_profiles = 3;
2481
2482                 if (argc > 0) {
2483                         profile.Number = atoi(argv[0]) - 1;
2484                         start = profile.Number;
2485                         stop = start + 1;
2486
2487                         if (profile.Number < 0) {
2488                                 fprintf(stderr, _("Profile number must be value from 1 to %d!\n"), max_profiles);
2489                                 GSM->Terminate();
2490                                 return -1;
2491                         }
2492
2493                         if (profile.Number >= max_profiles) {
2494                                 fprintf(stderr, _("This phone supports only %d profiles!\n"), max_profiles);
2495                                 GSM->Terminate();
2496                                 return -1;
2497                         }
2498                 } else {
2499                         start = 0;
2500                         stop = max_profiles;
2501                 }
2502
2503                 i = start;
2504                 while (i < stop) {
2505                         profile.Number = i;
2506
2507                         if (profile.Number != 0)
2508                                 GSM->GetProfile(&profile);
2509
2510                         fprintf(stdout, "%d. \"%s\"\n", profile.Number + 1, profile.Name);
2511                         if (profile.DefaultName == -1) fprintf(stdout, _(" (name defined)\n"));
2512
2513                         fprintf(stdout, _("Incoming call alert: %s\n"), GetProfileCallAlertString(profile.CallAlert));
2514
2515                         /* For different phones different ringtones names */
2516
2517                         if (!strcmp(model, "NSE-3"))
2518                                 fprintf(stdout, _("Ringing tone: %s (%d)\n"), RingingTones[profile.Ringtone], profile.Ringtone);
2519                         else
2520                                 fprintf(stdout, _("Ringtone number: %d\n"), profile.Ringtone);
2521
2522                         fprintf(stdout, _("Ringing volume: %s\n"), GetProfileVolumeString(profile.Volume));
2523
2524                         fprintf(stdout, _("Message alert tone: %s\n"), GetProfileMessageToneString(profile.MessageTone));
2525
2526                         fprintf(stdout, _("Keypad tones: %s\n"), GetProfileKeypadToneString(profile.KeypadTone));
2527
2528                         fprintf(stdout, _("Warning and game tones: %s\n"), GetProfileWarningToneString(profile.WarningTone));
2529
2530                         /* FIXME: Light settings is only used for Car */
2531                         if (profile.Number == (max_profiles - 2)) fprintf(stdout, _("Lights: %s\n"), profile.Lights ? _("On") : _("Automatic"));
2532
2533                         fprintf(stdout, _("Vibration: %s\n"), GetProfileVibrationString(profile.Vibration));
2534
2535                         /* FIXME: it will be nice to add here reading caller group name. */
2536                         if (max_profiles != 3) fprintf(stdout, _("Caller groups: 0x%02x\n"), profile.CallerGroups);
2537
2538                         /* FIXME: Automatic answer is only used for Car and Headset. */
2539                         if (profile.Number >= (max_profiles - 2)) fprintf(stdout, _("Automatic answer: %s\n"), profile.AutomaticAnswer ? _("On") : _("Off"));
2540
2541                         fprintf(stdout, "\n");
2542
2543                         i++;
2544                 }
2545         } else {
2546                 if (error == GE_NOTIMPLEMENTED) {
2547                         fprintf(stderr, _("Function not implemented in %s model!\n"), model);
2548                         GSM->Terminate();
2549                         return -1;
2550                 } else {
2551                         fprintf(stderr, _("Unspecified error\n"));
2552                         GSM->Terminate();
2553                         return -1;
2554                 }
2555         }
2556
2557         GSM->Terminate();
2558         return 0;
2559 }
2560
2561 /* Get requested range of memory storage entries and output to stdout in
2562    easy-to-parse format */
2563 int getmemory(int argc, char *argv[])
2564 {
2565         GSM_PhonebookEntry entry;
2566         int count;
2567         GSM_Error error;
2568         char *memory_type_string;
2569         int start_entry;
2570         int end_entry;
2571         GSM_Statemachine *sm = &State;
2572         
2573         /* Handle command line args that set type, start and end locations. */
2574         memory_type_string = argv[0];
2575         entry.MemoryType = StrToMemoryType(memory_type_string);
2576         if (entry.MemoryType == GMT_XX) {
2577                 fprintf(stderr, _("Unknown memory type %s (use ME, SM, ...)!\n"), argv[0]);
2578                 return (-1);
2579         }
2580
2581         start_entry = atoi (argv[1]);
2582         if (argc > 2) end_entry = atoi (argv[2]);
2583         else end_entry = start_entry;
2584
2585         /* Now retrieve the requested entries. */
2586         for (count = start_entry; count <= end_entry; count ++) {
2587
2588                 entry.Location = count;
2589
2590                 data.PhonebookEntry=&entry;
2591                 error=SM_Functions(GOP_ReadPhonebook,&data,sm);
2592
2593                 if (error == GE_NONE) {
2594                         fprintf(stdout, "%s;%s;%s;%d;%d\n", entry.Name, entry.Number, memory_type_string, entry.Location, entry.Group);
2595                         if (entry.MemoryType == GMT_MC || entry.MemoryType == GMT_DC || entry.MemoryType == GMT_RC)
2596                                 fprintf(stdout, "%02u.%02u.%04u %02u:%02u:%02u\n", entry.Date.Day, entry.Date.Month, entry.Date.Year, entry.Date.Hour, entry.Date.Minute, entry.Date.Second);
2597                 }  
2598                 else {
2599                         if (error == GE_NOTIMPLEMENTED) {
2600                                 fprintf(stderr, _("Function not implemented in %s model!\n"), model);
2601                                 return -1;
2602                         }
2603                         else if (error == GE_INVALIDMEMORYTYPE) {
2604                                 fprintf(stderr, _("Memory type %s not supported!\n"), memory_type_string);
2605                                 return -1;
2606                         }
2607
2608                         fprintf(stdout, _("%s|%d|Bad location or other error!(%d)\n"), memory_type_string, count, error);
2609                 }
2610         }
2611         return 0;
2612 }
2613
2614 /* Read data from stdin, parse and write to phone.  The parsing is relatively
2615    crude and doesn't allow for much variation from the stipulated format. */
2616 /* FIXME: I guess there's *very* similar code in xgnokii */
2617 int writephonebook(int argc, char *args[])
2618 {
2619         GSM_PhonebookEntry entry;
2620         GSM_Error error;
2621         char *memory_type_string;
2622         int line_count=0;
2623         int subentry;
2624
2625         char *Line, OLine[100], BackLine[100];
2626         char *ptr;
2627
2628         /* Check argument */
2629         if (argc && (strcmp("-i", args[0])))
2630                 usage();
2631
2632         Line = OLine;
2633
2634         /* Go through data from stdin. */
2635         while (GetLine(stdin, Line, 99)) {
2636                 strcpy(BackLine, Line);
2637                 line_count++;
2638
2639                 ptr = strtok(Line, ";");
2640                 if (ptr) strcpy(entry.Name, ptr);
2641                 else entry.Name[0] = 0;
2642
2643                 ptr = strtok(NULL, ";");
2644                 if (ptr) strcpy(entry.Number, ptr);
2645                 else entry.Number[0] = 0;
2646
2647                 ptr = strtok(NULL, ";");
2648
2649                 if (!ptr) {
2650                         fprintf(stderr, _("Format problem on line %d [%s]\n"), line_count, BackLine);
2651                         Line = OLine;
2652                         continue;
2653                 }
2654
2655                 if (!strncmp(ptr,"ME", 2)) {
2656                         memory_type_string = "int";
2657                         entry.MemoryType = GMT_ME;
2658                 } else {
2659                         if (!strncmp(ptr,"SM", 2)) {
2660                                 memory_type_string = "sim";
2661                                 entry.MemoryType = GMT_SM;
2662                         } else {
2663                                 fprintf(stderr, _("Format problem on line %d [%s]\n"), line_count, BackLine);
2664                                 break;
2665                         }
2666                 }
2667
2668                 ptr = strtok(NULL, ";");
2669                 if (ptr) entry.Location = atoi(ptr);
2670                 else entry.Location = 0;
2671
2672                 ptr = strtok(NULL, ";");
2673                 if (ptr) entry.Group = atoi(ptr);
2674                 else entry.Group = 0;
2675
2676                 if (!ptr) {
2677                         fprintf(stderr, _("Format problem on line %d [%s]\n"), line_count, BackLine);
2678                         continue;
2679                 }
2680
2681                 for (subentry = 0; ; subentry++) {
2682                         ptr = strtok(NULL, ";");
2683
2684                         if (ptr &&  *ptr != 0)
2685                                 entry.SubEntries[subentry].EntryType = atoi(ptr);
2686                         else
2687                                 break;
2688
2689                         ptr = strtok(NULL, ";");
2690                         if (ptr)
2691                                 entry.SubEntries[subentry].NumberType=atoi(ptr);
2692
2693                         /* Phone Numbers need to have a number type. */
2694                         if (!ptr && entry.SubEntries[subentry].EntryType == GSM_Number) {
2695                                 fprintf(stderr, _("Missing phone number type on line %d"
2696                                                   " entry %d [%s]\n"), line_count, subentry, BackLine);
2697                                 subentry--;
2698                                 break;
2699                         }
2700
2701                         ptr = strtok(NULL, ";");
2702                         if (ptr)
2703                                 entry.SubEntries[subentry].BlockNumber=atoi(ptr);
2704
2705                         ptr = strtok(NULL, ";");
2706
2707                         /* 0x13 Date Type; it is only for Dailed Numbers, etc.
2708                            we don't store to this memories so it's an error to use it. */
2709                         if (!ptr || entry.SubEntries[subentry].EntryType == GSM_Date) {
2710                                 fprintf(stdout, _("There is no phone number on line %d entry %d [%s]\n"),
2711                                         line_count, subentry, BackLine);
2712                                 subentry--;
2713                                 break;
2714                         } else
2715                                 strcpy(entry.SubEntries[subentry].data.Number, ptr);
2716                 }
2717
2718                 entry.SubEntriesCount = subentry;
2719
2720                 /* This is to send other exports (like from 6110) to 7110 */
2721                 if (!entry.SubEntriesCount) {
2722                         entry.SubEntriesCount = 1;
2723                         entry.SubEntries[subentry].EntryType   = GSM_Number;
2724                         entry.SubEntries[subentry].NumberType  = GSM_General;
2725                         entry.SubEntries[subentry].BlockNumber = 2;
2726                         strcpy(entry.SubEntries[subentry].data.Number, entry.Number);
2727                 }
2728
2729                 Line = OLine;
2730
2731                 if (argc) {
2732                         GSM_PhonebookEntry aux;
2733
2734                         aux.Location = entry.Location;
2735                         error = GSM->GetMemoryLocation(&aux);
2736                         
2737                         if (error == GE_NONE) {
2738                                 if (!aux.Empty) {
2739                                         int confirm = -1;
2740                                         char ans[8];
2741
2742                                         fprintf(stdout, _("Location busy. "));
2743                                         while (confirm < 0) {
2744                                                 fprintf(stdout, _("Overwrite? (yes/no) "));
2745                                                 GetLine(stdin, ans, 7);
2746                                                 if (!strcmp(ans, _("yes"))) confirm = 1;
2747                                                 else if (!strcmp(ans, _("no"))) confirm = 0;
2748                                         }
2749                                         if (!confirm) continue;
2750                                 }
2751                         } else {
2752                                 fprintf(stderr, _("Unknown error (%d)\n"), error);
2753                                 GSM->Terminate();
2754                                 return 0;
2755                         }
2756                 }
2757
2758                 /* Do write and report success/failure. */
2759                 error = GSM->WritePhonebookLocation(&entry);
2760
2761                 if (error == GE_NONE)
2762                         fprintf (stdout, _("Write Succeeded: memory type: %s, loc: %d, name: %s, number: %s\n"), memory_type_string, entry.Location, entry.Name, entry.Number);
2763                 else
2764                         fprintf (stdout, _("Write FAILED(%d): memory type: %s, loc: %d, name: %s, number: %s\n"), error, memory_type_string, entry.Location, entry.Name, entry.Number);
2765
2766         }
2767
2768         GSM->Terminate();
2769         return 0;
2770 }
2771
2772 /* Getting speed dials. */
2773 int getspeeddial(char *Number)
2774 {
2775         GSM_SpeedDial   SpeedDial;
2776         GSM_Data        data;
2777         GSM_Error       error;
2778         
2779         SpeedDial.Number = atoi(Number);
2780         
2781         if (GSM && GSM->GetSpeedDial && GSM->Terminate) {
2782                 error = GSM->GetSpeedDial(&SpeedDial);
2783                 GSM->Terminate();
2784         } else {
2785                 GSM_DataClear(&data);
2786                 data.SpeedDial = &SpeedDial;
2787                 
2788                 error = SM_Functions(GOP_GetSpeedDial, &data, &State);
2789         }
2790         
2791         switch (error) {
2792         case GE_NONE:
2793                 fprintf(stdout, _("SpeedDial nr. %d: %d:%d\n"), SpeedDial.Number, SpeedDial.MemoryType, SpeedDial.Location);
2794                 break;
2795         case GE_NOTIMPLEMENTED:
2796                 fprintf(stdout, _("Function not implemented in %s !\n"), model);
2797                 break;
2798         default:
2799                 fprintf(stdout, _("Internal error\n"));
2800                 break;
2801         }
2802         
2803         return error;
2804 }
2805
2806 /* Setting speed dials. */
2807 int setspeeddial(char *argv[])
2808 {
2809         GSM_SpeedDial entry;
2810
2811         char *memory_type_string;
2812
2813         /* Handle command line args that set type, start and end locations. */
2814
2815         if (strcmp(argv[1], "ME") == 0) {
2816                 entry.MemoryType = 0x02;
2817                 memory_type_string = "ME";
2818         } else if (strcmp(argv[1], "SM") == 0) {
2819                 entry.MemoryType = 0x03;
2820                 memory_type_string = "SM";
2821         } else {
2822                 fprintf(stderr, _("Unknown memory type %s!\n"), argv[1]);
2823                 return -1;
2824         }
2825
2826         entry.Number = atoi(argv[0]);
2827         entry.Location = atoi(argv[2]);
2828
2829         if (GSM->SetSpeedDial(&entry) == GE_NONE) {
2830                 fprintf(stdout, _("Succesfully written!\n"));
2831         }
2832
2833         GSM->Terminate();
2834         return 0;
2835 }
2836
2837 /* Getting the status of the display. */
2838 int getdisplaystatus(void)
2839
2840         int Status;
2841
2842         GSM->GetDisplayStatus(&Status);
2843
2844         fprintf(stdout, _("Call in progress: %s\n"), Status & (1<<DS_Call_In_Progress)?_("on"):_("off"));
2845         fprintf(stdout, _("Unknown: %s\n"),          Status & (1<<DS_Unknown)?_("on"):_("off"));
2846         fprintf(stdout, _("Unread SMS: %s\n"),       Status & (1<<DS_Unread_SMS)?_("on"):_("off"));
2847         fprintf(stdout, _("Voice call: %s\n"),       Status & (1<<DS_Voice_Call)?_("on"):_("off"));
2848         fprintf(stdout, _("Fax call active: %s\n"),  Status & (1<<DS_Fax_Call)?_("on"):_("off"));
2849         fprintf(stdout, _("Data call active: %s\n"), Status & (1<<DS_Data_Call)?_("on"):_("off"));
2850         fprintf(stdout, _("Keyboard lock: %s\n"),    Status & (1<<DS_Keyboard_Lock)?_("on"):_("off"));
2851         fprintf(stdout, _("SMS storage full: %s\n"), Status & (1<<DS_SMS_Storage_Full)?_("on"):_("off"));
2852
2853         GSM->Terminate();
2854         return 0;
2855 }
2856
2857 int netmonitor(char *Mode)
2858 {
2859         unsigned char mode = atoi(Mode);
2860         char Screen[50];
2861
2862         if (!strcmp(Mode, "reset"))
2863                 mode = 0xf0;
2864         else if (!strcmp(Mode, "off"))
2865                 mode = 0xf1;
2866         else if (!strcmp(Mode, "field"))
2867                 mode = 0xf2;
2868         else if (!strcmp(Mode, "devel"))
2869                 mode = 0xf3;
2870         else if (!strcmp(Mode, "next"))
2871                 mode = 0x00;
2872
2873         memset(&Screen, 0, 50);
2874         GSM->NetMonitor(mode, Screen);
2875
2876         if (Screen)
2877                 fprintf(stdout, "%s\n", Screen);
2878
2879         GSM->Terminate();
2880         return 0;
2881 }
2882
2883 int identify(void)
2884 {
2885         /* Hopefully is 64 larger as FB38_MAX* / FB61_MAX* */
2886         char imei[64], model[64], rev[64], manufacturer[64];
2887         GSM_Statemachine *sm = &State;
2888
2889         data.Manufacturer=manufacturer;
2890         data.Model=model;
2891         data.Revision=rev;
2892         data.Imei=imei;
2893
2894         /* Retrying is bad idea: what if function is simply not implemented?
2895            Anyway let's wait 2 seconds for the right packet from the phone. */
2896         sleep(2);
2897
2898         strcpy(imei, "(unknown)");
2899         strcpy(manufacturer, "(unknown)");
2900         strcpy(model, "(unknown)");
2901         strcpy(rev, "(unknown)");
2902
2903         SM_Functions(GOP_Identify, &data, sm);
2904
2905         fprintf(stdout, _("IMEI:     %s\n"), imei);
2906         fprintf(stdout, _("Manufacturer: %s\n"), manufacturer);
2907         fprintf(stdout, _("Model:    %s\n"), model);
2908         fprintf(stdout, _("Revision: %s\n"), rev);
2909
2910         //GSM->Terminate();
2911
2912         return 0;
2913 }
2914
2915 int senddtmf(char *String)
2916 {
2917         GSM->SendDTMF(String);
2918         GSM->Terminate();
2919         return 0;
2920 }
2921
2922 /* Resets the phone */
2923 int reset( char *type)
2924 {
2925         unsigned char _type = 0x03;
2926
2927         if (type) {
2928                 if(!strcmp(type, "soft"))
2929                         _type = 0x03;
2930                 else
2931                         if(!strcmp(type, "hard"))
2932                                 _type = 0x04;
2933                         else {
2934                                 fprintf(stderr, _("What kind of reset do you want??\n"));
2935                                 return -1;
2936                         }
2937         }
2938
2939         GSM->Reset(_type);
2940         GSM->Terminate();
2941
2942         return 0;
2943 }
2944
2945 /* pmon allows fbus code to run in a passive state - it doesn't worry about
2946    whether comms are established with the phone.  A debugging/development
2947    tool. */
2948 int pmon(void)
2949
2950
2951         GSM_Error error;
2952         GSM_ConnectionType connection=GCT_Serial;
2953         GSM_Statemachine sm;
2954
2955         /* Initialise the code for the GSM interface. */     
2956         error = GSM_Initialise(model, Port, Initlength, connection, NULL, &sm);
2957
2958         if (error != GE_NONE) {
2959                 fprintf(stderr, _("GSM/FBUS init failed! (Unknown model ?). Quitting.\n"));
2960                 return -1;
2961         }
2962
2963         while (1) {
2964                 usleep(50000);
2965         }
2966
2967         return 0;
2968 }
2969
2970 int sendringtone(int argc, char *argv[])
2971 {
2972         GSM_SMSMessage SMS;
2973         GSM_Ringtone ringtone;
2974         int i;
2975         int size = GSM_MAX_RINGTONE_PACKAGE_LENGTH;
2976         char Package[GSM_MAX_RINGTONE_PACKAGE_LENGTH];
2977
2978         struct option options[] = {
2979                 SMSC_OPTIONS,
2980                 { NULL,       0,                 NULL, 0}
2981         };
2982
2983         /* Default settings for SMS message:
2984            - no delivery report
2985            - Class Message 1
2986            - no compression
2987            - 8 bit data
2988            - SMSC no. 1
2989            - validity 3 days
2990            - set UserDataHeaderIndicator
2991         */
2992
2993         SMS.Type = GST_MO;
2994         SMS.Class = 1;
2995         SMS.Compression = false;
2996         SMS.EightBit = true;
2997         SMS.MessageCenter.No = 1;
2998         SMS.Validity = 4320; /* 4320 minutes == 72 hours */
2999
3000         SMS_SetupUDH(&SMS,GSM_RingtoneUDH);             /* error ignored */
3001
3002         optarg = NULL;
3003         optind = 0;
3004         argv[1]=argv[0];
3005         argv++;
3006         argc--;
3007         while ((i = getopt_long(argc, argv, "", options, NULL)) != -1) {
3008                 if (smsc_options_parse(i,&SMS))
3009                         continue;
3010                 switch (i) {
3011                 default:
3012                         usage(); /* Would be better to have an sendsms_usage() here. */
3013                 }
3014         }
3015         argc-=optind;
3016         argv+=optind;
3017
3018         if (argc!=2)
3019                 usage();
3020
3021         if (GSM_ReadRingtoneFile(argv[1], &ringtone)) {
3022                 fprintf(stdout, _("Failed to load ringtone.\n"));
3023                 return(-1);
3024         }  
3025         if (strlen(argv[0])+1 > sizeof(SMS.Destination)) {
3026                 fprintf(stdout, _("Destination number \"%s\" length too long!\n"), argv[0]);
3027                 return(-1);
3028         }
3029         strcpy(SMS.Destination, argv[0]);
3030         GSM_PackRingtone(&ringtone, Package, &size);
3031
3032         sendsms_deconcatenated(&SMS,Package,size,true/*useudh*/);
3033
3034         GSM->Terminate();
3035         return 0;
3036 }
3037
3038
3039 int setringtone(int argc, char *argv[])
3040 {
3041         GSM_Ringtone ringtone;
3042         GSM_Error error;
3043
3044         if (GSM_ReadRingtoneFile(argv[0], &ringtone)) {
3045                 fprintf(stdout, _("Failed to load ringtone.\n"));
3046                 return(-1);
3047         }  
3048
3049         error = GSM->SetRingtone(&ringtone);
3050
3051         if (error == GE_NONE) 
3052                 fprintf(stdout, _("Send succeeded!\n"));
3053         else
3054                 fprintf(stdout, _("Send failed\n"));
3055
3056         GSM->Terminate();
3057         return 0;
3058 }
3059
3060 int presskeysequence(void)
3061 {
3062         char buf[105];
3063
3064         console_raw();
3065
3066         memset(&buf[0], 0, 102);
3067         while (read(0, buf, 100) > 0) {
3068                 fprintf(stderr, "handling keys (%d).\n", strlen(buf));
3069                 if (GSM->HandleString(buf) != GE_NONE)
3070                         fprintf(stdout, _("Key press simulation failed.\n"));
3071                 memset(buf, 0, 102);
3072         }
3073
3074         GSM->Terminate();
3075         return 0;
3076 }
3077  
3078 /* This is a "convenience" function to allow quick test of new API stuff which
3079    doesn't warrant a "proper" command line function. */
3080 #ifndef WIN32
3081 int foogle(char *argv[])
3082 {
3083         /* Initialise the code for the GSM interface. */     
3084         fbusinit(NULL);
3085         // Fill in what you would like to test here...
3086         return 0;
3087 }
3088 #endif
3089