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