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