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