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