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