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