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