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