\r\n -> \n
[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   CurrentPhonebookEntry=NULL;
331   CurrentNetworkInfo = NULL;
332   CurrentGetBitmap=NULL;
333   CurrentPlayToneError=GE_UNKNOWN;
334   strcpy(CurrentIncomingCall," ");
335   CurrentGetBinRingtone=NULL;
336   CurrentNetworkInfo=NULL;
337   CurrentRequestTerminate=false;
338   CurrentDisableKeepAlive=false;
339   CurrentCalendarNotesInfo.HowMany=2000;
340   CurrentMagicError = GE_BUSY;  
341   
342   if (!strcmp(model,"auto")) {
343
344     /* For now */
345     GSM = &N6110_Functions;
346     GSM_Info = &N6110_Information;
347     GSM_LinkOK = &CurrentLinkOK;
348 #ifdef DEBUG
349     fprintf(stdout,_("Trying FBUS for new Nokia phones...\n"));
350 #endif
351     /* Trying FBUS */
352     Protocol = &FBUS_Functions;
353     CurrentConnectionType=GCT_FBUS;    
354     connection2=GCT_FBUS;
355     if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
356     {
357       found_match=true;
358     } else {
359       GSM->Terminate();      
360     }
361
362     if (!found_match) {
363       usleep(100);          
364       
365       /* For now */
366       GSM = &N6110_Functions;
367       GSM_Info = &N6110_Information;
368       GSM_LinkOK = &CurrentLinkOK;
369 #ifdef DEBUG
370       fprintf(stdout,_("Trying DLR3 for new Nokia phones...\n"));
371 #endif
372       /* Trying DLR3 */
373       Protocol = &FBUS_Functions;
374       CurrentConnectionType=GCT_DLR3;    
375       connection2=GCT_DLR3;
376       if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
377       {
378         found_match=true;
379       } else {
380         GSM->Terminate();      
381       }
382     }
383     
384     if (!found_match) {
385       usleep(100);          
386       
387       /* For now */
388       GSM = &N6110_Functions;
389       GSM_Info = &N6110_Information;
390       GSM_LinkOK = &CurrentLinkOK;
391 #ifdef DEBUG
392       fprintf(stdout,_("Trying MBUS for new Nokia phones...\n"));
393 #endif
394       /* Trying MBUS */
395       Protocol = &MBUS_Functions;
396       CurrentConnectionType=GCT_MBUS;    
397       connection2=GCT_MBUS;
398       if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
399       {
400         found_match=true;
401       } else {
402         GSM->Terminate();      
403       }
404     }
405
406     if (!found_match) return GE_NOTSUPPORTED;
407
408     usleep(50);
409         
410   } else {
411 #ifdef DEBUG
412     if (CheckModel (Nsniff_Information, model, connection)) {
413       /* Set pointers to relevant addresses */
414       GSM = &Nsniff_Functions;
415       GSM_Info = &Nsniff_Information;
416       GSM_LinkOK = &CurrentLinkOK;
417       found_match=true;
418     }
419 #endif
420
421     if (CheckModel (N6110_Information, model, connection)) {
422       /* Set pointers to relevant addresses */
423       GSM = &N6110_Functions;
424       GSM_Info = &N6110_Information;
425       GSM_LinkOK = &CurrentLinkOK;
426       found_match=true;
427     }
428     if (CheckModel (N7110_Information, model, connection)) {
429       /* Set pointers to relevant addresses */
430       GSM = &N7110_Functions;
431       GSM_Info = &N7110_Information;
432       GSM_LinkOK = &CurrentLinkOK;
433       found_match=true;
434     }
435     if (CheckModel (Nat_Information, model, connection)) {
436       /* Set pointers to relevant addresses */
437       GSM = &Nat_Functions;
438       GSM_Info = &Nat_Information;
439       GSM_LinkOK = &CurrentLinkOK;
440       found_match=true;
441     }
442
443     if (found_match) {
444       switch (connection) {
445         case GCT_FBUS    : Protocol = &FBUS_Functions;    break;
446         case GCT_Infrared: Protocol = &FBUS_Functions;    break;
447         case GCT_Tekram  : Protocol = &FBUS_Functions;    break;
448         case GCT_DLR3    : Protocol = &FBUS_Functions;    break;
449         case GCT_MBUS    : Protocol = &MBUS_Functions;    break;
450         case GCT_Irda    : Protocol = &FBUSIRDA_Functions;break;
451         case GCT_AT      : Protocol = &AT_Functions;      break;
452         case GCT_Default : Protocol = NULL;               break;
453       }
454     } else
455       return GE_NOTSUPPORTED;
456   }
457
458     
459   /* Now call model specific initialisation code. */
460   error=(GSM->Initialise(device, initlength, connection2, rlp_callback));
461
462   /* RTH: FIXME: second try for Irda (6210 only?)*/
463   if ( error!=GE_NONE && connection == GCT_Irda)
464   {
465    #ifdef DEBUG
466      fprintf(stdout,"Irda connection: second try!\n");
467    #endif
468    device_close();
469    error=(GSM->Initialise(device, initlength, connection2, rlp_callback));
470   }
471
472   if (error==GE_NONE && !strcmp(SynchronizeTime,"yes"))
473   {
474     nowh=time(NULL);
475     now=localtime(&nowh);
476
477     Date.Year = now->tm_year;
478     Date.Month = now->tm_mon+1;
479     Date.Day = now->tm_mday;
480     Date.Hour = now->tm_hour;
481     Date.Minute = now->tm_min;
482     Date.Second = now->tm_sec;
483
484     if (Date.Year<1900)
485     {
486
487       /* Well, this thing is copyrighted in U.S. This technique is known as
488          Windowing and you can read something about it in LinuxWeekly News:
489          http://lwn.net/1999/features/Windowing.phtml. This thing is beeing
490          written in Czech republic and Poland where algorithms are not allowed
491          to be patented. */
492
493       if (Date.Year>90)
494         Date.Year = Date.Year+1900;
495       else
496         Date.Year = Date.Year+2000;
497     }
498
499     /* FIXME: Error checking should be here. */
500     GSM->SetDateTime(&Date);
501   }
502
503   return error;
504 }
505
506 GSM_Error Unimplemented(void)
507 {
508         return GE_NOTIMPLEMENTED;
509 }
510
511 GSM_Error NotSupported(void)
512 {
513         return GE_NOTSUPPORTED;
514 }
515
516 /* Applications should call N6110_Terminate to shut down the N6110 thread and
517    close the serial port. */
518 void NULL_Terminate(void)
519 {
520   Protocol->Terminate();
521 }
522
523 #ifdef WIN32
524 /* Here are things made for keeping connecting */
525 void NULL_KeepAlive()
526 {
527 }
528 #else
529 /* Here are things made for keeping connecting */
530 void NULL_KeepAlive()
531 {
532 }
533 #endif
534
535 #ifdef DEBUG
536 void NULL_TX_DisplayMessage(u16 MessageLength, u8 *MessageBuffer)
537 {
538   fprintf(stdout, _("PC: "));
539
540   txhexdump(MessageLength,MessageBuffer);
541 }
542 #endif
543
544 bool NULL_WritePhone (u16 length, u8 *buffer) {
545   if (device_write(buffer,length)!=length) return false;
546                                       else return true;
547 }
548
549 GSM_Error NULL_WaitUntil (int time, GSM_Error *value)
550 {
551   int timeout;
552
553   timeout=time;
554   
555   /* Wait for timeout or other error. */
556   while (timeout != 0 && *value == GE_BUSY ) {
557           
558     if (--timeout == 0)
559       return (GE_TIMEOUT);
560                     
561     usleep (100000);
562   }
563
564   return *value;
565 }
566
567 GSM_Error NULL_SendMessageSequence (int time, GSM_Error *value,
568                  u16 message_length, u8 message_type, u8 *buffer)
569 {
570   *value=GE_BUSY;
571   
572   Protocol->SendMessage(message_length, message_type, buffer);  
573
574   return NULL_WaitUntil (time, value);
575 }
576
577 GSM_ConnectionType GetConnectionTypeFromString(char *Connection) {
578
579   GSM_ConnectionType connection=GCT_FBUS;
580
581   if (!strcmp(Connection, "irda"))     connection=GCT_Irda;
582   if (!strcmp(Connection, "infrared")) connection=GCT_Infrared;
583   if (!strcmp(Connection, "mbus"))     connection=GCT_MBUS;
584   if (!strcmp(Connection, "dlr3"))     connection=GCT_DLR3;
585   if (!strcmp(Connection, "at"))       connection=GCT_AT;
586   if (!strcmp(Connection, "tekram210"))connection=GCT_Tekram;
587   
588   return connection;
589 }
590
591 bool GetMemoryTypeString(char *memorytext, GSM_MemoryType *type)
592 {
593   int i=0;
594
595   typedef struct {
596     GSM_MemoryType type;
597     char *name;
598   } GSM_MTStrings;
599
600   GSM_MTStrings mystring[] = {
601     {GMT_ME,"ME"},
602     {GMT_SM,"SM"},
603     {GMT_FD,"FD"},
604     {GMT_ON,"ON"},
605     {GMT_EN,"EN"},
606     {GMT_DC,"DC"},
607     {GMT_RC,"RC"},  
608     {GMT_MC,"MC"},
609     {GMT_LD,"LD"},
610     {GMT_MT,"MT"},
611     {GMT_ME,"undefined"}
612   };
613
614   while (strcmp(mystring[i].name,"undefined")) {
615     if (*type==mystring[i].type) {
616       strcpy(memorytext,mystring[i].name);
617       return true;
618     }
619     i++;
620   }
621   return false;
622 }
623
624 bool GetMemoryTypeID(char *memorytext, GSM_MemoryType *type)
625 {
626   int i=0;
627
628   typedef struct {
629     GSM_MemoryType type;
630     char *name;
631   } GSM_MTStrings;
632
633   GSM_MTStrings mystring[] = {
634     {GMT_ME,"ME"},
635     {GMT_SM,"SM"},
636     {GMT_FD,"FD"},
637     {GMT_ON,"ON"},
638     {GMT_EN,"EN"},
639     {GMT_DC,"DC"},
640     {GMT_RC,"RC"},  
641     {GMT_MC,"MC"},
642     {GMT_LD,"LD"},
643     {GMT_MT,"MT"},
644     {GMT_ME,"undefined"}
645   };
646
647   while (strcmp(mystring[i].name,"undefined")) {
648     if (strcmp(mystring[i].name,memorytext)==0) {
649       *type=mystring[i].type;
650       return true;
651     }
652     i++;
653   }
654
655   return false;
656 }
657
658 char *GetMygnokiiVersion() {
659
660   static char Buffer[1000]="";
661
662   sprintf(Buffer, "%s",VERSION);
663
664   return Buffer;
665 }
666
667 /*
668 1.Name,2.CodeName,3.Calendar,4.Netmonitor,5.Caller groups,6.Phonebook,
669 7.Authentication 8.Datacalls 9.KeysPressing 10.SMSC Default Recipient
670 11.SpeedDials 12.ScreenSavers 13.DTMF 14.SMS 15.NoPowerFrame 16.StartUpLogo
671 17.Profiles 18.Ringtones 19.WAP
672 */
673
674 static OnePhoneModel allmodels[] = {
675
676 /*1,    2,       3,      4,       5,        6       7      8        9      10        11      12       13     14      15        16       17       18        19 */
677 {"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}},
678 {"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}},
679 {"3310","NHM-5",{F_CAL33,F_NETMON,        0,F_PBK33,     0,       0,     0,F_SMSCDEF,F_SPEED,F_SCRSAV,     0,F_SMS  ,F_NOPOWER,F_STANIM,F_PROF33,F_RING_SM,    0}},
680 {"3330","NHM-6",{F_CAL33,F_NETMON,        0,F_PBK33,     0,       0,F_KEYB,F_SMSCDEF,F_SPEED,F_SCRSAV,     0,F_SMS  ,        0,F_STANIM,F_PROF33,F_RING_SM,F_WAP}},
681 {"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}},
682 {"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}},
683 {"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}},
684 {"6110","NSE-3",{F_CAL61,F_NETMON,F_CALER61,      0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,F_STA   ,F_PROF61,F_RINGBIN,    0}},
685 {"6130","NSK-3",{F_CAL61,F_NETMON,F_CALER61,      0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,F_STA   ,F_PROF61,F_RINGBIN,    0}},
686 {"6150","NSM-1",{F_CAL61,F_NETMON,F_CALER61,      0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,F_STA   ,F_PROF61,F_RINGBIN,    0}},
687 {"6190","NSB-3",{F_CAL61,F_NETMON,F_CALER61,      0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED,       0,F_DTMF,F_SMS  ,        0,F_STA   ,F_PROF61,F_RINGBIN,    0}},
688 {"6210","NPE-3",{F_CAL71,F_NETMON,F_CALER61,F_PBK71,     0,F_DATA71,     0,F_SMSCDEF,F_SPEED,       0,     0,F_SMS71,        0,F_STA62 ,F_PROF61,F_RINGBIN,F_WAP}},
689 {"6250","NHM-3",{F_CAL71,F_NETMON,F_CALER61,F_PBK71,     0,F_DATA71,     0,F_SMSCDEF,F_SPEED,       0,     0,F_SMS71,        0,F_STA62 ,F_PROF61,F_RINGBIN,F_WAP}},     
690 {"7110","NSE-5",{F_CAL71,F_NETMON,F_CALER61,F_PBK71,     0,F_DATA71,     0,F_SMSCDEF,F_SPEED,       0,     0,F_SMS71,        0,F_STA71 ,F_PROF61,F_RINGBIN,F_WAP}},
691 {"8210","NSM-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}},
692 {"8850","NSM-2",{      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}},
693 {"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}},//quesses only !
694 {""    ,""     ,{      0,       0,        0,      0,     0,       0,     0,        0,      0,       0,     0,      0,        0,       0,       0,        0,    0}}
695 };
696
697 OnePhoneModel *GetPhoneModelData (const char *num)
698 {
699         register int i = 0;
700
701         while (allmodels[i].number != "") {
702                 if (strcmp (num, allmodels[i].number) == 0) {
703                         return (&allmodels[i]);
704                 }
705                 i++;
706         }
707
708         return (&allmodels[i]);
709 }
710
711 char *GetModelName ()
712 {
713   static char model[64];
714
715   while (GSM->GetModel(model)  != GE_NONE) sleep(1);
716
717   return (GetPhoneModelData(model)->model);
718 }
719
720 int GetModelFeature (featnum_index num)
721 {
722   static char model[64];
723
724   while (GSM->GetModel(model)  != GE_NONE) sleep(1);
725
726   return (GetPhoneModelData(model)->features[num]);
727 }
728
729 int LogAvailable=-1; //-1 not checked earlier, 0 not, 1 yes
730 char *logfilename;
731
732 bool AppendLog(u8 *buffer, int length,bool format)
733 {
734   FILE *file=NULL;
735   char buffer2[50001];
736   int i;
737
738   struct CFG_Header *cfg_info;
739   char *LogFile;        
740
741   if (LogAvailable==-1) {
742
743     LogAvailable=0;
744
745     cfg_info=CFG_FindGnokiirc();
746     if (cfg_info==NULL) return false;
747
748     LogFile = CFG_Get(cfg_info, "global", "logfile");
749     if (LogFile) {
750       LogAvailable=1;
751       logfilename=LogFile;
752
753       file=fopen(logfilename, "a+");
754
755       /* We have first entry in this session and too large file */
756       if (fread( buffer2, 1, 50000,file )==50000) {
757         fclose(file);
758         file=fopen(logfilename, "w");
759       }
760     }
761   } else {
762     if (LogAvailable==1) {
763       file=fopen(logfilename, "a");
764     }
765   }
766   
767   if (LogAvailable==1) {
768     for (i=0;i<length;i++) {
769       if (format) {
770         fprintf(file, "%02x",buffer[i]);
771         switch (buffer[i]) {
772           case 0x09:fprintf(file,_(" |"));break;
773           default:
774             if (isprint(buffer[i])) fprintf(file, _("%c|"),buffer[i]);
775                                else fprintf(file, _(" |"));
776             break;
777         } 
778       } else {
779         fprintf(file, "%c",buffer[i]);
780       }
781     }
782     if (format) fprintf(file, "\n");
783     fclose(file);
784   }
785
786   return (LogAvailable==1);
787 }
788
789 bool AppendLogText(u8 *buffer,bool format)
790 {
791   return AppendLog(buffer,strlen(buffer),format);
792 }