http://marcin-wiacek.fkn.pl/english/zips/mygnokii.tar.gz
[gnokii.git] / common / gsm-api.c
1 /*
2
3   G N O K I I
4
5   A Linux/Unix toolset and driver for Nokia mobile phones.
6
7   Released under the terms of the GNU GPL, see file COPYING for more details.
8         
9   Provides a generic API for accessing functions on the phone, wherever
10   possible hiding the model specific details.
11
12   The underlying code should run in it's own thread to allow communications to
13   the phone to be run independantly of mailing code that calls these API
14   functions.
15
16   Unless otherwise noted, all functions herein block until they complete.  The
17   functions themselves are defined in a structure in gsm-common.h.
18
19 */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <time.h>
25
26 #ifdef WIN32
27   #include <windows.h>
28   #include "misc_win32.h"
29 #endif
30
31 #include "gsm-api.h"
32
33 #include "newmodules/n6110.h"
34 #include "newmodules/n7110.h"
35 #include "newmodules/newat.h"
36 #ifdef DEBUG
37   #include "newmodules/sniff/sniff.h"
38 #endif
39 #include "protocol/fbusirda.h"
40 #include "protocol/fbus.h"
41 #include "protocol/mbus.h"
42 #include "protocol/at.h"
43 #include "files/cfgreader.h"
44
45 #ifndef WIN32
46   #include "devices/device.h"
47 #endif
48
49 #ifdef VC6
50   /* for VC6 make scripts save VERSION constant in mversion.h file */
51   #include "mversion.h"
52 #endif
53
54 /* GSM_LinkOK is set to true once normal communications with the phone have
55    been established. */
56
57 bool *GSM_LinkOK;
58
59 /* Define pointer to the GSM_Functions structure used by external code to call
60    relevant API functions. This structure is defined in gsm-common.h. */
61
62 GSM_Functions *GSM;
63
64 /* Define pointer to the GSM_Information structure used by external code to
65    obtain information that varies from model to model. This structure is also
66    defined in gsm-common.h */
67
68 GSM_Information         *GSM_Info;
69
70 /* Initialise interface to the phone. Model number should be a string such as
71    3810, 5110, 6110 etc. Device is the serial port to use e.g. /dev/ttyS0, the
72    user must have write permission to the device. */
73
74 GSM_Protocol *Protocol;
75
76 /* Local variables used by get/set phonebook entry code. Buffer is used as a
77    source or destination for phonebook data and other functions... Error is
78    set to GE_NONE by calling function, set to GE_COMPLETE or an error code by
79    handler routines as appropriate. */
80                                    
81 GSM_PhonebookEntry *CurrentPhonebookEntry;
82 GSM_Error          CurrentPhonebookError;
83
84 GSM_SpeedDial      *CurrentSpeedDialEntry;
85 GSM_Error          CurrentSpeedDialError;
86
87 unsigned char      Current_IMEI[GSM_MAX_IMEI_LENGTH];
88 unsigned char      Current_Revision[GSM_MAX_REVISION_LENGTH];
89 unsigned char      Current_Model[GSM_MAX_MODEL_LENGTH];
90
91 GSM_SMSMessage     *CurrentSMSMessage;
92 GSM_Error          CurrentSMSMessageError;
93 int                CurrentSMSPointer;
94
95 GSM_SMSFolders      *CurrentSMSFolders;
96 GSM_Error          CurrentSMSFoldersError;
97 int                CurrentSMSFoldersCount;
98
99 GSM_OneSMSFolder   CurrentSMSFolder;
100 GSM_Error          CurrentSMSFolderError;
101 int                CurrentSMSFolderID;
102
103 GSM_MemoryStatus   *CurrentMemoryStatus;
104 GSM_Error          CurrentMemoryStatusError;
105
106 GSM_NetworkInfo    *CurrentNetworkInfo;
107 GSM_Error          CurrentNetworkInfoError;
108
109 GSM_SMSStatus      *CurrentSMSStatus;
110 GSM_Error          CurrentSMSStatusError;
111
112 GSM_MessageCenter  *CurrentMessageCenter;
113 GSM_Error          CurrentMessageCenterError;
114
115 int                *CurrentSecurityCodeStatus;
116 GSM_Error          CurrentSecurityCodeError;
117 GSM_SecurityCode   *CurrentSecurityCode;
118
119 GSM_DateTime       *CurrentDateTime;
120 GSM_Error          CurrentDateTimeError;
121
122 GSM_DateTime       *CurrentAlarm;
123 GSM_Error          CurrentAlarmError;
124
125 GSM_CalendarNote   *CurrentCalendarNote;
126 GSM_Error          CurrentCalendarNoteError;
127
128 GSM_NotesInfo      CurrentCalendarNotesInfo,*CurrentCalendarNotesInfo2;
129 GSM_Error          CurrentCalendarNotesInfoError;
130
131 GSM_Error          CurrentSetDateTimeError;
132 GSM_Error          CurrentSetAlarmError;
133
134 GSM_Error          CurrentEnableExtendedCommandsError;
135
136 int                CurrentRFLevel,
137                    CurrentBatteryLevel,
138                    CurrentPowerSource;
139
140 int                CurrentDisplayStatus;
141 GSM_Error          CurrentDisplayStatusError;
142
143 GSM_Error          CurrentResetPhoneSettingsError;
144
145 char               *CurrentNetmonitor;
146 GSM_Error          CurrentNetmonitorError;
147
148 GSM_Bitmap         *CurrentGetBitmap=NULL;
149 GSM_Error          CurrentGetBitmapError;
150
151 GSM_Error          CurrentSetBitmapError;
152
153 GSM_Error          CurrentSendDTMFError;
154
155 GSM_Profile        *CurrentProfile;
156 GSM_Error          CurrentProfileError;
157
158 GSM_Error          CurrentDisplayOutputError;
159
160 GSM_CBMessage      *CurrentCBMessage;
161 GSM_Error          CurrentCBError;
162
163 int                CurrentPressKeyEvent;
164 GSM_Error          CurrentPressKeyError;
165
166 GSM_Error          CurrentPlayToneError=GE_UNKNOWN;
167
168 GSM_Error          CurrentDialVoiceError;
169
170 GSM_Error          CurrentGetOperatorNameError;
171 GSM_Network        *CurrentGetOperatorNameNetwork;
172 GSM_Error          CurrentSetOperatorNameError;
173
174 GSM_Error          CurrentGetIMEIError;
175
176 GSM_Error          CurrentGetHWError;
177
178 unsigned char      CurrentPPS[4];
179 GSM_Error          CurrentProductProfileSettingsError;
180
181 char               CurrentIncomingCall[20];
182
183 GSM_Error          CurrentBinRingtoneError;
184 GSM_BinRingtone    *CurrentGetBinRingtone=NULL;
185
186 GSM_Error          CurrentRingtoneError;
187
188 GSM_Error          CurrentMagicError;
189
190 GSM_Error          CurrentSimlockInfoError;
191 GSM_AllSimlocks    *CurrentSimLock;
192
193 GSM_Error          CurrentGetWAPBookmarkError;
194 GSM_Error          CurrentSetWAPBookmarkError;
195 GSM_WAPBookmark    *WAPBookmark;
196
197 GSM_Error          CurrentGetWAPSettingsError;
198 GSM_WAPSettings    *WAPSettings;
199
200 GSM_Error          CurrentCallDivertError;
201 GSM_CallDivert    *CurrentCallDivert;
202
203 char              *CurrentManufacturer;
204
205 /* This is the connection type used in gnokii. */
206 GSM_ConnectionType CurrentConnectionType;
207
208 /* Pointer to a callback function used to return changes to a calls status */
209 /* This saves unreliable polling */
210 void (*CurrentCallPassup)(char c);
211
212 /* Pointer to callback function in user code to be called when RLP frames
213    are received. */
214 void (*CurrentRLP_RXCallback)(RLP_F96Frame *frame);
215
216 /* Used to disconnect the call */
217 u8 CurrentCallSequenceNumber;
218
219 bool CurrentLinkOK;
220
221 bool CurrentRequestTerminate;
222
223 bool CurrentDisableKeepAlive;
224
225 bool CheckModel (GSM_Information InfoToCheck, char *model, GSM_ConnectionType connection) {
226
227   bool found_match=false;
228
229   if (strstr(InfoToCheck.FBUSModels, model) != NULL) {
230     if (connection==GCT_FBUS) found_match=true;
231   }
232   if (strstr(InfoToCheck.MBUSModels, model) != NULL) {
233     if (connection==GCT_MBUS) found_match=true;
234   }
235   if (strstr(InfoToCheck.InfraredModels, model) != NULL) {
236     if (connection==GCT_Infrared) found_match=true;
237   }
238   if (strstr(InfoToCheck.DLR3Models, model) != NULL) {
239     if (connection==GCT_DLR3) found_match=true;
240   }
241   if (strstr(InfoToCheck.IrdaModels, model) != NULL) {
242     if (connection==GCT_Irda) found_match=true;
243   }
244   if (strstr(InfoToCheck.ATModels, model) != NULL) {
245     if (connection==GCT_AT) found_match=true;
246   }
247   if (strstr(InfoToCheck.TekramModels, model) != NULL) {
248     if (connection==GCT_Tekram) found_match=true;
249   }
250
251   return found_match;
252 }
253  
254 GSM_Error TryNewNokia(char *model, char *device, char *initlength, GSM_ConnectionType connection, void (*rlp_callback)(RLP_F96Frame *frame)) {
255   int InitLength;
256   int count;
257   unsigned char init_char = N6110_SYNC_BYTE;
258
259   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
260   char phonemodel[64];
261
262   if (Protocol->Initialise(device,initlength,connection,rlp_callback)!=GE_NONE)
263   {
264     return GE_NOTSUPPORTED; 
265   }
266
267   if (connection!=GCT_MBUS) {
268     InitLength = atoi(initlength);
269
270     if ((strcmp(initlength, "default") == 0) || (InitLength == 0)) {
271       InitLength = 250; /* This is the usual value, lower may work. */
272     }
273
274 #ifdef DEBUG
275     fprintf(stdout,_("Writing init chars...."));
276 #endif
277
278     /* Initialise link with phone or what have you */
279     /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
280        empirical. */
281     for (count = 0; count < InitLength; count ++) {
282       usleep(100);
283       Protocol->WritePhone(1,&init_char);
284     }
285
286 #ifdef DEBUG
287     fprintf(stdout,_("Done\n"));  
288 #endif
289
290     N6110_SendStatusRequest();
291   }
292
293   usleep(100);
294
295   if (N6110_SendIDFrame()!=GE_NONE)
296     return GE_TIMEOUT;
297  
298   while (N6110_GetModel(phonemodel) != GE_NONE)
299     sleep(1);
300
301   if (!strcmp(phonemodel,"NPE-3") || !strcmp(phonemodel,"NSE-5"))
302   {
303     GSM->Terminate();      
304     
305     /* Set pointers to relevant addresses */
306     GSM = &N7110_Functions;
307     GSM_Info = &N7110_Information;
308     GSM_LinkOK = &CurrentLinkOK;
309     return GE_NONE;
310   }
311
312   return GE_NONE;
313 }
314
315 GSM_Error GSM_Initialise(char *model, char *device, char *initlength, GSM_ConnectionType connection, void (*rlp_callback)(RLP_F96Frame *frame), char* SynchronizeTime)
316 {
317   bool found_match=false;
318   
319   GSM_ConnectionType connection2;
320
321   struct tm *now;
322   time_t nowh;
323   GSM_DateTime Date;
324   GSM_Error error;
325   
326   connection2=connection;
327
328   CurrentRLP_RXCallback = rlp_callback;
329   CurrentCallPassup=NULL;
330   CurrentCallDivert=NULL;
331   CurrentPhonebookEntry=NULL;
332   CurrentNetworkInfo = NULL;
333   CurrentGetBitmap=NULL;
334   CurrentPlayToneError=GE_UNKNOWN;
335   strcpy(CurrentIncomingCall," ");
336   CurrentGetBinRingtone=NULL;
337   CurrentNetworkInfo=NULL;
338   CurrentRequestTerminate=false;
339   CurrentDisableKeepAlive=false;
340   CurrentCalendarNotesInfo.HowMany=2000;
341   CurrentSMSMessage=NULL;
342   CurrentMagicError = GE_BUSY;  
343   
344   if (!strcmp(model,"auto")) {
345
346     /* For now */
347     GSM = &N6110_Functions;
348     GSM_Info = &N6110_Information;
349     GSM_LinkOK = &CurrentLinkOK;
350 #ifdef DEBUG
351     fprintf(stdout,_("Trying FBUS for new Nokia phones...\n"));
352 #endif
353     /* Trying FBUS */
354     Protocol = &FBUS_Functions;
355     CurrentConnectionType=GCT_FBUS;    
356     connection2=GCT_FBUS;
357     if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
358     {
359       found_match=true;
360     } else {
361       GSM->Terminate();      
362     }
363
364     if (!found_match) {
365       usleep(100);          
366       
367       /* For now */
368       GSM = &N6110_Functions;
369       GSM_Info = &N6110_Information;
370       GSM_LinkOK = &CurrentLinkOK;
371 #ifdef DEBUG
372       fprintf(stdout,_("Trying DLR3 for new Nokia phones...\n"));
373 #endif
374       /* Trying DLR3 */
375       Protocol = &FBUS_Functions;
376       CurrentConnectionType=GCT_DLR3;    
377       connection2=GCT_DLR3;
378       if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
379       {
380         found_match=true;
381       } else {
382         GSM->Terminate();      
383       }
384     }
385     
386     if (!found_match) {
387       usleep(100);          
388       
389       /* For now */
390       GSM = &N6110_Functions;
391       GSM_Info = &N6110_Information;
392       GSM_LinkOK = &CurrentLinkOK;
393 #ifdef DEBUG
394       fprintf(stdout,_("Trying MBUS for new Nokia phones...\n"));
395 #endif
396       /* Trying MBUS */
397       Protocol = &MBUS_Functions;
398       CurrentConnectionType=GCT_MBUS;    
399       connection2=GCT_MBUS;
400       if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
401       {
402         found_match=true;
403       } else {
404         GSM->Terminate();      
405       }
406     }
407
408     if (!found_match) return GE_NOTSUPPORTED;
409
410     usleep(50);
411         
412   } else {
413     if (!strcmp(model,"modelauto")) {
414       /* For now */
415       GSM = &N6110_Functions;
416       GSM_Info = &N6110_Information;
417       GSM_LinkOK = &CurrentLinkOK;
418 #ifdef DEBUG
419       fprintf(stdout,_("Trying to find connected model...\n"));
420 #endif
421       switch (connection) {
422         case GCT_FBUS    : Protocol = &FBUS_Functions;    break;
423         case GCT_Infrared: Protocol = &FBUS_Functions;    break;
424         case GCT_Tekram  : Protocol = &FBUS_Functions;    break;
425         case GCT_DLR3    : Protocol = &FBUS_Functions;    break;
426         case GCT_MBUS    : Protocol = &MBUS_Functions;    break;
427         case GCT_Irda    : Protocol = &FBUSIRDA_Functions;break;
428         case GCT_AT      : Protocol = &AT_Functions;      break;
429         case GCT_Default : Protocol = NULL;               break;
430       }
431       CurrentConnectionType=connection;    
432       connection2=connection;
433       if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
434       {
435         found_match=true;
436       } else {
437         GSM->Terminate();      
438       }
439
440       if (!found_match) return GE_NOTSUPPORTED;
441
442       usleep(50);
443
444     } else {
445 #ifdef DEBUG
446       if (CheckModel (Nsniff_Information, model, connection)) {
447         /* Set pointers to relevant addresses */
448         GSM = &Nsniff_Functions;
449         GSM_Info = &Nsniff_Information;
450         GSM_LinkOK = &CurrentLinkOK;
451         found_match=true;
452       }
453 #endif
454
455       if (CheckModel (N6110_Information, model, connection)) {
456         /* Set pointers to relevant addresses */
457         GSM = &N6110_Functions;
458         GSM_Info = &N6110_Information;
459         GSM_LinkOK = &CurrentLinkOK;
460         found_match=true;
461       }
462       if (CheckModel (N7110_Information, model, connection)) {
463         /* Set pointers to relevant addresses */
464         GSM = &N7110_Functions;
465         GSM_Info = &N7110_Information;
466         GSM_LinkOK = &CurrentLinkOK;
467         found_match=true;
468       }
469       if (CheckModel (Nat_Information, model, connection)) {
470         /* Set pointers to relevant addresses */
471         GSM = &Nat_Functions;
472         GSM_Info = &Nat_Information;
473         GSM_LinkOK = &CurrentLinkOK;
474         found_match=true;
475       }
476
477       if (found_match) {
478         switch (connection) {
479           case GCT_FBUS    : Protocol = &FBUS_Functions;    break;
480           case GCT_Infrared: Protocol = &FBUS_Functions;    break;
481           case GCT_Tekram  : Protocol = &FBUS_Functions;    break;
482           case GCT_DLR3    : Protocol = &FBUS_Functions;    break;
483           case GCT_MBUS    : Protocol = &MBUS_Functions;    break;
484           case GCT_Irda    : Protocol = &FBUSIRDA_Functions;break;
485           case GCT_AT      : Protocol = &AT_Functions;      break;
486           case GCT_Default : Protocol = NULL;               break;
487         }
488       } else
489         return GE_NOTSUPPORTED;
490     }
491   }
492
493     
494   /* Now call model specific initialisation code. */
495   error=(GSM->Initialise(device, initlength, connection2, rlp_callback));
496
497   /* RTH: FIXME: second try for Irda (6210 only?)*/
498   if ( error!=GE_NONE && connection == GCT_Irda)
499   {
500    #ifdef DEBUG
501      fprintf(stdout,"Irda connection: second try!\n");
502    #endif
503    device_close();
504    error=(GSM->Initialise(device, initlength, connection2, rlp_callback));
505   }
506
507   if (error==GE_NONE && !strcmp(SynchronizeTime,"yes"))
508   {
509     nowh=time(NULL);
510     now=localtime(&nowh);
511
512     Date.Year = now->tm_year;
513     Date.Month = now->tm_mon+1;
514     Date.Day = now->tm_mday;
515     Date.Hour = now->tm_hour;
516     Date.Minute = now->tm_min;
517     Date.Second = now->tm_sec;
518
519     if (Date.Year<1900)
520     {
521
522       /* Well, this thing is copyrighted in U.S. This technique is known as
523          Windowing and you can read something about it in LinuxWeekly News:
524          http://lwn.net/1999/features/Windowing.phtml. This thing is beeing
525          written in Czech republic and Poland where algorithms are not allowed
526          to be patented. */
527
528       if (Date.Year>90)
529         Date.Year = Date.Year+1900;
530       else
531         Date.Year = Date.Year+2000;
532     }
533
534     /* FIXME: Error checking should be here. */
535     GSM->SetDateTime(&Date);
536   }
537
538   return error;
539 }
540
541 GSM_Error Unimplemented(void)
542 {
543         return GE_NOTIMPLEMENTED;
544 }
545
546 GSM_Error NotSupported(void)
547 {
548         return GE_NOTSUPPORTED;
549 }
550
551 /* Applications should call N6110_Terminate to shut down the N6110 thread and
552    close the serial port. */
553 void NULL_Terminate(void)
554 {
555   Protocol->Terminate();
556 }
557
558 #ifdef WIN32
559 /* Here are things made for keeping connecting */
560 void NULL_KeepAlive()
561 {
562 }
563 #else
564 /* Here are things made for keeping connecting */
565 void NULL_KeepAlive()
566 {
567 }
568 #endif
569
570 #ifdef DEBUG
571 void NULL_TX_DisplayMessage(u16 MessageLength, u8 *MessageBuffer)
572 {
573   fprintf(stdout, _("PC: "));
574
575   txhexdump(MessageLength,MessageBuffer);
576 }
577 #endif
578
579 bool NULL_WritePhone (u16 length, u8 *buffer) {
580   if (device_write(buffer,length)!=length) return false;
581                                       else return true;
582 }
583
584 GSM_Error NULL_WaitUntil (int time, GSM_Error *value)
585 {
586   int timeout;
587
588   timeout=time;
589   
590   /* Wait for timeout or other error. */
591   while (timeout != 0 && *value == GE_BUSY ) {
592           
593     if (--timeout == 0)
594       return (GE_TIMEOUT);
595                     
596     usleep (100000);
597   }
598
599   return *value;
600 }
601
602 GSM_Error NULL_SendMessageSequence (int time, GSM_Error *value,
603                  u16 message_length, u8 message_type, u8 *buffer)
604 {
605   *value=GE_BUSY;
606   
607   Protocol->SendMessage(message_length, message_type, buffer);  
608
609   return NULL_WaitUntil (time, value);
610 }
611
612 GSM_ConnectionType GetConnectionTypeFromString(char *Connection) {
613
614   GSM_ConnectionType connection=GCT_FBUS;
615
616   if (!strcmp(Connection, "irda"))     connection=GCT_Irda;
617   if (!strcmp(Connection, "infrared")) connection=GCT_Infrared;
618   if (!strcmp(Connection, "mbus"))     connection=GCT_MBUS;
619   if (!strcmp(Connection, "dlr3"))     connection=GCT_DLR3;
620   if (!strcmp(Connection, "at"))       connection=GCT_AT;
621   if (!strcmp(Connection, "tekram210"))connection=GCT_Tekram;
622   
623   return connection;
624 }
625
626 bool GetMemoryTypeString(char *memorytext, GSM_MemoryType *type)
627 {
628   int i=0;
629
630   typedef struct {
631     GSM_MemoryType type;
632     char *name;
633   } GSM_MTStrings;
634
635   GSM_MTStrings mystring[] = {
636     {GMT_ME,"ME"},
637     {GMT_SM,"SM"},
638     {GMT_FD,"FD"},
639     {GMT_ON,"ON"},
640     {GMT_EN,"EN"},
641     {GMT_DC,"DC"},
642     {GMT_RC,"RC"},  
643     {GMT_MC,"MC"},
644     {GMT_LD,"LD"},
645     {GMT_MT,"MT"},
646     {GMT_ME,"undefined"}
647   };
648
649   while (strcmp(mystring[i].name,"undefined")) {
650     if (*type==mystring[i].type) {
651       strcpy(memorytext,mystring[i].name);
652       return true;
653     }
654     i++;
655   }
656   return false;
657 }
658
659 bool GetMemoryTypeID(char *memorytext, GSM_MemoryType *type)
660 {
661   int i=0;
662
663   typedef struct {
664     GSM_MemoryType type;
665     char *name;
666   } GSM_MTStrings;
667
668   GSM_MTStrings mystring[] = {
669     {GMT_ME,"ME"},
670     {GMT_SM,"SM"},
671     {GMT_FD,"FD"},
672     {GMT_ON,"ON"},
673     {GMT_EN,"EN"},
674     {GMT_DC,"DC"},
675     {GMT_RC,"RC"},  
676     {GMT_MC,"MC"},
677     {GMT_LD,"LD"},
678     {GMT_MT,"MT"},
679     {GMT_ME,"undefined"}
680   };
681
682   while (strcmp(mystring[i].name,"undefined")) {
683     if (strcmp(mystring[i].name,memorytext)==0) {
684       *type=mystring[i].type;
685       return true;
686     }
687     i++;
688   }
689
690   return false;
691 }
692
693 char *GetMygnokiiVersion() {
694
695   static char Buffer[1000]="";
696
697   sprintf(Buffer, "%s",VERSION);
698
699   return Buffer;
700 }
701
702 /*
703 1.Name,2.CodeName,3.Calendar,4.Netmonitor,5.Caller groups,6.Phonebook,
704 7.Authentication 8.Datacalls 9.KeysPressing 10.SMSC Default Recipient
705 11.SpeedDials 12.ScreenSavers 13.DTMF 14.SMS 15.NoPowerFrame 16.StartUpLogo
706 17.Profiles 18.Ringtones 19.WAP 20.RIngtonesNumber
707 */
708
709 static OnePhoneModel allmodels[] = {
710
711 /*1,    2,       3,      4,       5,        6          7      8        9      10        11      12       13     14      15        16       17       18        19    20 */
712 {"3210","NSE-8",{      0,F_NETMON,        0,         0,     0,       0,     0,F_SMSCDEF,F_SPEED,       0,     0,F_SMS  ,F_NOPOWER,F_STANIM,F_PROF51,F_RINGBIN,    0, 2}},
713 {"3210","NSE-9",{      0,F_NETMON,        0,         0,     0,       0,     0,F_SMSCDEF,F_SPEED,       0,     0,F_SMS  ,F_NOPOWER,F_STANIM,F_PROF51,F_RINGBIN,    0, 2}},
714 {"3310","NHM-5",{F_CAL33,F_NETMON,        0,F_PBK33SIM,     0,       0,     0,F_SMSCDEF,F_SPEED,F_SCRSAV,     0,F_SMS  ,F_NOPOWER,F_STANIM,F_PROF33,F_RING_SM,    0, 7}},
715 {"3330","NHM-6",{F_CAL33,F_NETMON,        0,F_PBK33INT,     0,       0,F_KEYB,F_SMSCDEF,F_SPEED,F_SCRSAV,     0,F_SMS  ,        0,F_STANIM,F_PROF33,F_RING_SM,F_WAP, 7}},
716 {"5110","NSE-1",{      0,F_NETMON,        0,         0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,       0,F_PROF51,        0,    0, 0}},
717 {"5130","NSK-1",{      0,F_NETMON,        0,         0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,       0,F_PROF51,        0,    0, 0}},
718 {"5190","NSB-1",{      0,F_NETMON,        0,         0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,       0,F_PROF51,        0,    0, 0}},
719 {"6110","NSE-3",{F_CAL61,F_NETMON,F_CALER61,F_PBK61INT,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,F_STA   ,F_PROF61,F_RINGBIN,    0, 1}},
720 {"6130","NSK-3",{F_CAL61,F_NETMON,F_CALER61,F_PBK61INT,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,F_STA   ,F_PROF61,F_RINGBIN,    0, 1}},
721 {"6150","NSM-1",{F_CAL61,F_NETMON,F_CALER61,F_PBK61INT,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,F_STA   ,F_PROF61,F_RINGBIN,    0, 1}},
722 {"6190","NSB-3",{F_CAL61,F_NETMON,F_CALER61,F_PBK61INT,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,F_STA   ,F_PROF61,F_RINGBIN,    0, 1}},
723 {"6210","NPE-3",{F_CAL71,F_NETMON,F_CALER61,F_PBK71INT,     0,F_DATA71,     0,F_SMSCDEF,F_SPEED,       0,     0,F_SMS71,        0,F_STA62 ,F_PROF61,F_RINGBIN,F_WAP, 5}},
724 {"6250","NHM-3",{F_CAL71,F_NETMON,F_CALER61,F_PBK71INT,     0,F_DATA71,     0,F_SMSCDEF,F_SPEED,       0,     0,F_SMS71,        0,F_STA62 ,F_PROF61,F_RINGBIN,F_WAP, 5}},       
725 {"7110","NSE-5",{F_CAL71,F_NETMON,F_CALER61,F_PBK71INT,     0,F_DATA71,     0,F_SMSCDEF,F_SPEED,       0,     0,F_SMS71,        0,F_STA71 ,F_PROF61,F_RINGBIN,F_WAP, 5}},
726 {"8210","NSM-3",{      0,F_NETMON,F_CALER61,F_PBK61INT,     0,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,F_STA   ,F_PROF61,F_RINGBIN,    0, 1}},
727 {"8850","NSM-2",{      0,F_NETMON,F_CALER61,F_PBK61INT,     0,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,F_STA   ,F_PROF61,F_RINGBIN,    0, 1}},
728 {"9210","RAE-3",{      0,F_NETMON,F_CALER61,         0,     0,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,F_STA   ,F_PROF61,F_RINGBIN,    0, 0}},//quesses only !
729 {""    ,""     ,{      0,       0,        0,         0,     0,       0,     0,        0,      0,       0,     0,      0,        0,       0,       0,        0,    0, 0}}
730 };
731
732 OnePhoneModel *GetPhoneModelData (const char *num)
733 {
734         register int i = 0;
735
736         while (allmodels[i].number != "") {
737                 if (strcmp (num, allmodels[i].number) == 0) {
738                         return (&allmodels[i]);
739                 }
740                 i++;
741         }
742
743         return (&allmodels[i]);
744 }
745
746 char *GetModelName ()
747 {
748   static char model[64];
749
750   while (GSM->GetModel(model)  != GE_NONE) sleep(1);
751
752   return (GetPhoneModelData(model)->model);
753 }
754
755 int GetModelFeature (featnum_index num)
756 {
757   static char model[64];
758
759   while (GSM->GetModel(model)  != GE_NONE) sleep(1);
760
761   return (GetPhoneModelData(model)->features[num]);
762 }
763
764 int LogAvailable=-1; //-1 not checked earlier, 0 not, 1 yes
765 char *logfilename;
766
767 bool AppendLog(u8 *buffer, int length,bool format)
768 {
769   FILE *file=NULL;
770   char buffer2[50001];
771   int i;
772
773   struct CFG_Header *cfg_info;
774   char *LogFile;        
775
776   if (LogAvailable==-1) {
777
778     LogAvailable=0;
779
780     cfg_info=CFG_FindGnokiirc();
781     if (cfg_info==NULL) return false;
782
783     LogFile = CFG_Get(cfg_info, "global", "logfile");
784     if (LogFile) {
785       LogAvailable=1;
786       logfilename=LogFile;
787
788       file=fopen(logfilename, "a+");
789
790       /* We have first entry in this session and too large file */
791       if (fread( buffer2, 1, 50000,file )==50000) {
792         fclose(file);
793         file=fopen(logfilename, "w");
794       }
795     }
796   } else {
797     if (LogAvailable==1) {
798       file=fopen(logfilename, "a");
799     }
800   }
801   
802   if (LogAvailable==1) {
803     for (i=0;i<length;i++) {
804       if (format) {
805         fprintf(file, "%02x",buffer[i]);
806         switch (buffer[i]) {
807           case 0x09:fprintf(file,_(" |"));break;
808           default:
809             if (isprint(buffer[i])) fprintf(file, _("%c|"),buffer[i]);
810                                else fprintf(file, _(" |"));
811             break;
812         } 
813       } else {
814         fprintf(file, "%c",buffer[i]);
815       }
816     }
817     if (format) fprintf(file, "\n");
818     fclose(file);
819   }
820
821   return (LogAvailable==1);
822 }
823
824 bool AppendLogText(u8 *buffer,bool format)
825 {
826   return AppendLog(buffer,strlen(buffer),format);
827 }