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