481c92e593f772ee0e1a2752aab5ada0417df81b
[gnokii.git] / common / newmodules / n6110.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   This file provides an API for accessing functions on the 6110 and similar
10   phones.
11
12 */
13
14 #include "config.h"
15
16 /* "Turn on" prototypes in n-6110.h */
17
18 #define __n_6110_c 
19
20 /* System header files */
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25 #ifdef WIN32
26   #include "misc_win32.h"
27 #endif
28  
29 /* Various header file */
30 #ifndef VC6
31   #include "config.h"
32 #endif
33
34 #include "gsm-api.h"
35 #include "gsm-coding.h"
36 #include "newmodules/n6110.h"
37 #include "newmodules/n7110.h"
38 #include "protocol/fbus.h"
39 #include "devices/device.h"
40 /* Global variables used by code in gsm-api.c to expose the functions
41    supported by this model of phone. */
42
43
44
45
46
47
48
49 /* Here we initialise model specific functions. */
50 GSM_Functions N6110_Functions = {
51   N6110_Initialise,
52   N6110_DispatchMessage,
53   NULL_Terminate,
54   NULL_KeepAlive,
55   N6110_GetMemoryLocation,
56   N6110_WritePhonebookLocation,
57 #ifndef UCLINUX
58   N6110_GetSpeedDial,
59   N6110_SetSpeedDial,
60 #else /* UCLINUX */
61   NULL,
62   NULL,
63 #endif /* UCLINUX */
64   N6110_GetMemoryStatus,
65 #ifndef UCLINUX
66   N6110_GetSMSStatus,
67   N6110_GetSMSCenter,
68   N6110_SetSMSCenter,
69   N6110_GetSMSMessage,
70   N6110_DeleteSMSMessage,
71   N6110_SendSMSMessage,
72   N6110_SaveSMSMessage,
73 #else /* UCLINUX */
74   NULL,
75   NULL,
76   NULL,
77   NULL,
78   NULL,
79   NULL,
80   NULL,
81 #endif /* UCLINUX */
82   N6110_GetRFLevel,
83   N6110_GetBatteryLevel,
84   N6110_GetPowerSource,
85 #ifndef UCLINUX
86   N6110_GetDisplayStatus,
87   N6110_EnterSecurityCode,
88   N6110_GetSecurityCodeStatus,
89   N6110_GetSecurityCode,
90   N6110_GetIMEI,
91   N6110_GetRevision,
92   N6110_GetModel,
93   N6110_GetDateTime,
94   N6110_SetDateTime,
95   N6110_GetAlarm,
96   N6110_SetAlarm,
97   N6110_DialVoice,
98 #else /* UCLINUX */
99   NULL,
100   NULL,
101   NULL,
102   NULL,
103   NULL,
104   NULL,
105   NULL,
106   NULL,
107   NULL,
108   NULL,
109   NULL,
110   NULL,
111 #endif /* UCLINUX */
112   N6110_DialData,
113 #ifndef UCLINUX
114   N6110_GetIncomingCallNr,
115   N6110_GetNetworkInfo,
116   N6110_GetCalendarNote,
117   N6110_WriteCalendarNote,
118   N6110_DeleteCalendarNote,
119   N6110_NetMonitor,
120   N6110_SendDTMF,
121   N6110_GetBitmap,
122   N6110_SetBitmap,
123   N6110_SetRingTone,
124   N6110_SetBinRingTone,
125   N6110_GetBinRingTone,
126 #else /* UCLINUX */
127   NULL,
128   NULL,
129   NULL,
130   NULL,
131   NULL,
132   NULL,
133   NULL,
134   NULL,
135   NULL,
136   NULL,
137   NULL,
138   NULL,
139 #endif /* UCLINUX */
140   N6110_Reset,
141 #ifndef UCLINUX
142   N6110_GetProfile,
143   N6110_SetProfile,
144   N6110_SendRLPFrame,
145 #else /* UCLINUX */
146   NULL,
147   NULL,
148   NULL,
149 #endif /* UCLINUX */
150   N6110_CancelCall,
151 #ifndef UCLINUX
152   N6110_PressKey,
153   N6110_EnableDisplayOutput,
154   N6110_DisableDisplayOutput,
155   N6110_EnableCellBroadcast,
156   N6110_DisableCellBroadcast,
157   N6110_ReadCellBroadcast,
158   N6110_PlayTone,
159   N6110_GetProductProfileSetting,
160   N6110_SetProductProfileSetting,
161   N6110_GetOperatorName,
162   N6110_SetOperatorName,
163   N6110_GetVoiceMailbox,  N6110_Tests,
164   N6110_SimlockInfo,
165   UNIMPLEMENTED,                 //GetCalendarNotesInfo
166   N6110_GetSMSFolders,
167   N6110_ResetPhoneSettings,
168   N7110_GetWAPBookmark,
169   N7110_SetWAPBookmark,
170   N7110_GetWAPSettings,
171   N6110_CallDivert,
172   N6110_AnswerCall,
173 #else /* UCLINUX */
174   NULL,
175   NULL,
176   NULL,
177   NULL,
178   NULL,
179   NULL,
180   NULL,
181   NULL,
182   NULL,
183   NULL,
184   NULL,
185   NULL,  NULL,
186   NULL,
187   NULL,                 //GetCalendarNotesInfo
188   NULL,
189   NULL,
190   NULL,
191   NULL,
192   NULL,
193   NULL,
194   NULL,
195 #endif /* UCLINUX */
196   N6110_GetManufacturer
197 };
198
199 /* Mobile phone information */
200
201 GSM_Information N6110_Information = {
202   "3210|3310|3330|5110|5130|5190|6110|6130|6150|6190|8210|8850",
203      /* Supported models in FBUS */
204   "3210|3310|3330|5110|5130|5190|6110|6130|6150|6190|8210|8850",
205      /* Supported models in MBUS */
206   "6110|6130|6150|8210|8850",
207      /* Supported models in FBUS over infrared */
208   "",
209      /* Supported models in FBUS over DLR3 */
210   "",
211      /* AT commands */
212   "8210|8850",
213      /* infrared sockets */
214   "6110|6130|6150|8210|8850",
215      /* Supported models in FBUS over infrared with Tekram device */  
216   4,                     /* Max RF Level */
217   0,                     /* Min RF Level */
218   GRF_Arbitrary,         /* RF level units */
219   4,                     /* Max Battery Level */
220   0,                     /* Min Battery Level */
221   GBU_Arbitrary,         /* Battery level units */
222   GDT_DateTime,          /* Have date/time support */
223   GDT_TimeOnly,          /* Alarm supports time only */
224   1                      /* Only one alarm available */
225 };
226
227 #ifdef DEBUG
228 static const char *N6110_MemoryType_String [] = {
229   "",   /* 0x00 */
230   "MT", /* 0x01 */
231   "ME", /* 0x02 */
232   "SM", /* 0x03 */
233   "FD", /* 0x04 */
234   "ON", /* 0x05 */
235   "EN", /* 0x06 */
236   "DC", /* 0x07 */
237   "RC", /* 0x08 */
238   "MC", /* 0x09 */
239 };
240 #endif /* DEBUG */
241
242 /* Magic bytes from the phone. */
243 static unsigned char MagicBytes[4] = { 0x00, 0x00, 0x00, 0x00 };
244
245 /* For DisplayOutput */
246 #ifndef UCLINUX
247 static char               PhoneScreen[5+1][27+1];
248 static int                OldX=1000,OldY=0,NewX=0,NewY=0;
249 #endif /* UCLINUX */
250
251 void N6110_ReplyEnableExtendedCommands(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
252
253 #ifdef DEBUG
254   fprintf(stdout, _("Message: Answer for EnableExtendedSecurityCommands frame, meaning not known :-(\n"));
255 #endif /* DEBUG */
256
257   CurrentEnableExtendedCommandsError=GE_NONE;   
258 }
259
260 /* If you set make some things (for example,
261    change Security Code from phone's menu, disable and enable
262    phone), it won't answer for 0x40 frame - you won't be able
263    to play tones, get netmonitor, etc.
264
265    This function do thing called "Enabling extended security commands" -
266    it enables 0x40 frame functions.
267
268    This frame can also some other things - see below */
269 GSM_Error N6110_EnableExtendedCommands (unsigned char status)
270 {
271   unsigned char req[4] = { 0x00,
272                            0x01,0x64, /* Enable extended commands request */
273                            0x01 };    /* 0x01 - on, 0x00 - off,
274                                          0x03 & 0x04 - soft & hard reset,
275                                          0x06 - CONTACT SERVICE */
276
277   /* 0x06 MAKES CONTACT SERVICE! BE CAREFULL! */
278   /* When use 0x03 and had during session changed time & date
279      some phones (like 6150 or 6210) can ask for time & date after reset
280      or disable clock on the screen */
281   if (status!=0x06) req[3] = status;
282
283   return NULL_SendMessageSequence
284     (50, &CurrentEnableExtendedCommandsError, 4, 0x40, req);
285 }
286
287 void N6110_ReplyIMEI(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
288
289 #if defined WIN32 || !defined HAVE_SNPRINTF
290   sprintf(Current_IMEI, "%s", MessageBuffer+4);
291 #else
292   snprintf(Current_IMEI, GSM_MAX_IMEI_LENGTH, "%s", MessageBuffer+4);
293 #endif
294
295 #ifdef DEBUG
296   fprintf(stdout, _("Message: IMEI %s received\n"),Current_IMEI);
297 #endif
298
299   CurrentGetIMEIError=GE_NONE;       
300 }
301
302 GSM_Error N6110_SendIMEIFrame()
303 {
304   unsigned char req[4] = {0x00, 0x01, 0x66, 0x00};  
305
306   GSM_Error error;
307
308   error=N6110_EnableExtendedCommands(0x01);
309   if (error!=GE_NONE) return error;
310   
311   return NULL_SendMessageSequence (20, &CurrentGetIMEIError, 4, 0x40, req);
312 }
313
314 void N6110_ReplyHW(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
315
316   int i, j;
317     
318   if (MessageBuffer[3]==0x05) {
319
320 #ifdef DEBUG
321     fprintf(stdout,_("Message: Hardware version received: "));
322 #endif
323
324     j=strlen(Current_Revision);
325     Current_Revision[j++]=',';
326     Current_Revision[j++]=' ';
327     Current_Revision[j++]='H';
328     Current_Revision[j++]='W';
329             
330     for (i=5;i<9;i++) {
331 #ifdef DEBUG
332       fprintf(stdout,_("%c"), MessageBuffer[i]);
333 #endif
334       Current_Revision[j++]=MessageBuffer[i];
335     }
336
337 #ifdef DEBUG
338     fprintf(stdout,_("\n"));
339 #endif
340
341     CurrentGetHWError=GE_NONE;
342   }
343 }
344
345 GSM_Error N6110_SendHWFrame()
346 {
347   unsigned char req[4] = {0x00, 0x01, 0xc8, 0x05};  
348
349   GSM_Error error;
350
351   error=N6110_EnableExtendedCommands(0x01);
352   if (error!=GE_NONE) return error;
353   
354   return NULL_SendMessageSequence (20, &CurrentGetHWError, 4, 0x40, req);
355 }
356
357 void N6110_ReplyID(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
358
359   int i, j;
360  
361 #ifdef DEBUG
362   fprintf(stdout, _("Message: Mobile phone model identification received:\n"));
363   fprintf(stdout, _("   Firmware: "));
364 #endif
365
366   strcpy(Current_Revision,"SW");
367     
368   i=6;j=2;
369   while (MessageBuffer[i]!=0x0a) {
370     Current_Revision[j]=MessageBuffer[i];
371 #ifdef DEBUG
372     fprintf(stdout, _("%c"),MessageBuffer[i]);
373 #endif
374     if (j==GSM_MAX_REVISION_LENGTH-1) {
375 #ifdef DEBUG
376       fprintf(stderr,_("ERROR: increase GSM_MAX_REVISION_LENGTH!\n"));
377 #endif  
378       break;
379     }
380     j++;
381     i++;
382   }
383   Current_Revision[j+1]=0;
384
385 #ifdef DEBUG
386   fprintf(stdout, _("\n   Firmware date: "));
387 #endif
388
389   i++;
390   while (MessageBuffer[i]!=0x0a) {
391 #ifdef DEBUG
392     fprintf(stdout, _("%c"),MessageBuffer[i]);
393 #endif
394     i++;
395   }
396
397 #ifdef DEBUG
398   fprintf(stdout, _("\n   Model: "));
399 #endif /* DEBUG */
400
401   i++;j=0;
402   while (MessageBuffer[i]!=0x0a) {
403     Current_Model[j]=MessageBuffer[i];
404 #ifdef DEBUG
405     fprintf(stdout, _("%c"),MessageBuffer[i]);
406 #endif
407     if (j==GSM_MAX_MODEL_LENGTH-1) {
408 #ifdef DEBUG
409       fprintf(stderr,_("ERROR: increase GSM_MAX_MODEL_LENGTH!\n"));
410 #endif  
411       break;
412     }
413     j++;
414     i++;
415   }
416   Current_Model[j+1]=0;
417
418 #ifdef DEBUG
419   fprintf(stdout, _("\n"));
420 #endif /* DEBUG */
421     
422   CurrentMagicError=GE_NONE;
423 }
424
425 GSM_Error N6110_SendIDFrame()
426 {
427   unsigned char req[5] = {N6110_FRAME_HEADER, 0x03, 0x00};  
428
429   return NULL_SendMessageSequence (50, &CurrentMagicError, 5, 0xd1, req);
430 }
431
432 /* This function send the status request to the phone. */
433 /* Seems to be ignored in N3210 */
434 GSM_Error N6110_SendStatusRequest(void)
435 {
436   unsigned char req[] = {N6110_FRAME_HEADER, 0x01};
437
438   Protocol->SendMessage(4, 0x04, req);
439
440   return (GE_NONE);
441 }
442
443 static void N6110_ReplyGetAuthentication(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
444
445 #if defined WIN32 || !defined HAVE_SNPRINTF
446   sprintf(Current_IMEI, "%s", MessageBuffer+9);
447   sprintf(Current_Model, "%s", MessageBuffer+25);
448   sprintf(Current_Revision, "SW%s, HW%s", MessageBuffer+44, MessageBuffer+39);
449 #else
450   snprintf(Current_IMEI, GSM_MAX_IMEI_LENGTH, "%s", MessageBuffer+9);
451   snprintf(Current_Model, GSM_MAX_MODEL_LENGTH, "%s", MessageBuffer+25);
452   snprintf(Current_Revision, GSM_MAX_REVISION_LENGTH, "SW%s, HW%s", MessageBuffer+44, MessageBuffer+39);
453 #endif
454
455 #ifdef DEBUG
456   fprintf(stdout, _("Message: Mobile phone identification received:\n"));
457   fprintf(stdout, _("   IMEI: %s\n"), Current_IMEI);
458   fprintf(stdout, _("   Model: %s\n"), Current_Model);
459   fprintf(stdout, _("   Production Code: %s\n"), MessageBuffer+31);
460   fprintf(stdout, _("   HW: %s\n"), MessageBuffer+39);
461   fprintf(stdout, _("   Firmware: %s\n"), MessageBuffer+44);
462
463   /* These bytes are probably the source of the "Accessory not connected"
464      messages on the phone when trying to emulate NCDS... I hope....
465      UPDATE: of course, now we have the authentication algorithm. */
466   fprintf(stdout, _("   Magic bytes: %02x %02x %02x %02x\n"), MessageBuffer[50], MessageBuffer[51], MessageBuffer[52], MessageBuffer[53]);
467 #endif /* DEBUG */
468
469   MagicBytes[0]=MessageBuffer[50];
470   MagicBytes[1]=MessageBuffer[51];
471   MagicBytes[2]=MessageBuffer[52];
472   MagicBytes[3]=MessageBuffer[53];
473
474   CurrentMagicError=GE_NONE;
475 }
476
477 /* This function provides Nokia authentication protocol.
478
479    This code is written specially for gnokii project by Odinokov Serge.
480    If you have some special requests for Serge just write him to
481    apskaita@post.omnitel.net or serge@takas.lt
482
483    Reimplemented in C by Pavel Janík ml.
484
485    Nokia authentication protocol is used in the communication between Nokia
486    mobile phones (e.g. Nokia 6110) and Nokia Cellular Data Suite software,
487    commercially sold by Nokia Corp.
488
489    The authentication scheme is based on the token send by the phone to the
490    software. The software does it's magic (see the function
491    FB61_GetNokiaAuth()) and returns the result back to the phone. If the
492    result is correct the phone responds with the message "Accessory
493    connected!" displayed on the LCD. Otherwise it will display "Accessory not
494    supported" and some functions will not be available for use.
495
496    The specification of the protocol is not publicly available, no comment. */
497 static void N6110_GetNokiaAuth(unsigned char *Imei, unsigned char *MagicBytes, unsigned char *MagicResponse)
498 {
499
500   int i, j, CRC=0;
501
502   /* This is our temporary working area. */
503
504   unsigned char Temp[16];
505
506   /* Here we put FAC (Final Assembly Code) and serial number into our area. */
507
508   Temp[0]  = Imei[6];
509   Temp[1]  = Imei[7];
510   Temp[2]  = Imei[8];
511   Temp[3]  = Imei[9];
512   Temp[4]  = Imei[10];
513   Temp[5]  = Imei[11];
514   Temp[6]  = Imei[12];
515   Temp[7]  = Imei[13];
516
517   /* And now the TAC (Type Approval Code). */
518
519   Temp[8]  = Imei[2];
520   Temp[9]  = Imei[3];
521   Temp[10] = Imei[4];
522   Temp[11] = Imei[5];
523
524   /* And now we pack magic bytes from the phone. */
525
526   Temp[12] = MagicBytes[0];
527   Temp[13] = MagicBytes[1];
528   Temp[14] = MagicBytes[2];
529   Temp[15] = MagicBytes[3];
530
531   for (i=0; i<=11; i++)
532     if (Temp[i + 1]& 1)
533       Temp[i]<<=1;
534
535   switch (Temp[15] & 0x03) {
536
537   case 1:
538   case 2:
539     j = Temp[13] & 0x07;
540
541     for (i=0; i<=3; i++)
542       Temp[i+j] ^= Temp[i+12];
543
544     break;
545
546   default:
547     j = Temp[14] & 0x07;
548
549     for (i=0; i<=3; i++)
550       Temp[i + j] |= Temp[i + 12];
551   }
552
553   for (i=0; i<=15; i++)
554     CRC ^= Temp[i];
555
556   for (i=0; i<=15; i++) {
557
558     switch (Temp[15 - i] & 0x06) {
559
560     case 0:
561       j = Temp[i] | CRC;
562       break;
563
564     case 2:
565     case 4:
566       j = Temp[i] ^ CRC;
567       break;
568
569     case 6:
570       j = Temp[i] & CRC;
571       break;
572     }
573   
574     if (j == CRC)
575       j = 0x2c;
576
577     if (Temp[i] == 0)
578       j = 0;
579
580     MagicResponse[i] = j;
581
582   }
583 }
584
585 static GSM_Error N6110_Authentication()
586 {
587   unsigned char connect1[] = {N6110_FRAME_HEADER, 0x0d, 0x00, 0x00, 0x02};
588   unsigned char connect2[] = {N6110_FRAME_HEADER, 0x20, 0x02};
589   unsigned char connect3[] = {N6110_FRAME_HEADER, 0x0d, 0x01, 0x00, 0x02};
590   unsigned char connect4[] = {N6110_FRAME_HEADER, 0x10};
591   
592   unsigned char magic_connect[] = {N6110_FRAME_HEADER,
593   0x12,
594
595   /* The real magic goes here ... These bytes are filled in with the
596      function N6110_GetNokiaAuth(). */
597
598   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
600
601   /* NOKIA&GNOKII Accessory */
602
603   0x4e, 0x4f, 0x4b, 0x49, 0x41, 0x26, 0x4e, 0x4f, 0x4b, 0x49, 0x41, 0x20,
604   0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x79,
605   
606   0x00, 0x00, 0x00, 0x00};
607
608 #ifdef DEBUG
609   fprintf(stdout,_("Making authentication!\n"));
610 #endif
611
612   usleep(100); Protocol->SendMessage(7, 0x02, connect1);
613   usleep(100); Protocol->SendMessage(5, 0x02, connect2);
614   usleep(100); Protocol->SendMessage(7, 0x02, connect3);
615       
616   CurrentMagicError = GE_BUSY;
617
618   usleep(100); Protocol->SendMessage(4, 0x64, connect4);
619   if (NULL_WaitUntil(50,&CurrentMagicError)!=GE_NONE) return GE_TIMEOUT;
620
621   N6110_GetNokiaAuth(Current_IMEI, MagicBytes, magic_connect+4);
622
623   Protocol->SendMessage(45, 0x64, magic_connect);
624
625 #ifdef DEBUG
626   fprintf(stdout,_("End of authentication!\n"));
627 #endif
628
629   return GE_NONE;
630 }
631
632 /* Initialise variables and state machine. */
633 GSM_Error N6110_Initialise(char *port_device, char *initlength,
634                           GSM_ConnectionType connection,
635                           void (*rlp_callback)(RLP_F96Frame *frame))
636 {
637   unsigned char init_char = N6110_SYNC_BYTE;
638 #ifndef UCLINUX
639   unsigned char end_init_char = N6110_IR_END_SYNC_BYTE;
640 #endif /* UCLINUX */
641
642   int count;
643   int InitLength;
644   
645   if (Protocol->Initialise(port_device,initlength,connection,rlp_callback)!=GE_NONE)
646   {
647     return GE_NOTSUPPORTED;
648   }
649
650   switch (CurrentConnectionType) {
651 #ifndef UCLINUX
652     case GCT_Irda:
653     case GCT_MBUS:
654       /* We don't think about authentication in Irda, because
655          AFAIK there are no phones working over sockets
656          and having authentication. In MBUS it doesn't work */
657       usleep(100);
658
659       if (N6110_SendIDFrame()!=GE_NONE) return GE_TIMEOUT;
660     
661       if (N6110_SendIMEIFrame()!=GE_NONE) return GE_TIMEOUT;    
662
663       if (N6110_SendHWFrame()!=GE_NONE) return GE_TIMEOUT;    
664
665       CurrentLinkOK = true;                                 
666       break;
667 #endif /* UCLINUX */
668       
669     case GCT_FBUS:
670 #ifndef UCLINUX
671     case GCT_Infrared:
672     case GCT_Tekram:
673 #endif /* UCLINUX */
674       InitLength = atoi(initlength);
675
676       if ((strcmp(initlength, "default") == 0) || (InitLength == 0)) {
677         InitLength = 250;       /* This is the usual value, lower may work. */
678       }
679
680 #ifndef UCLINUX
681       if (CurrentConnectionType==GCT_Infrared ||
682           CurrentConnectionType==GCT_Tekram) {
683 #ifdef DEBUG
684         fprintf(stdout,_("Setting infrared for FBUS communication...\n"));
685 #endif
686         device_changespeed(9600);
687       }
688 #endif /* UCLINUX */
689
690 #ifdef DEBUG
691       fprintf(stdout,_("Writing init chars...."));
692 #endif
693
694       /* Initialise link with phone or what have you */
695       /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
696          empirical. */
697       for (count = 0; count < InitLength; count ++) {
698 #ifndef UCLINUX
699         if (CurrentConnectionType!=GCT_Infrared &&
700             CurrentConnectionType!=GCT_Tekram)
701 #endif /* UCLINUX */
702                                         usleep(100);
703         Protocol->WritePhone(1,&init_char);
704       }
705
706 #ifndef UCLINUX
707       if (CurrentConnectionType==GCT_Infrared ||
708           CurrentConnectionType==GCT_Tekram)      {
709         Protocol->WritePhone(1,&end_init_char);
710         usleep(200000);
711       }
712 #endif /* UCLINUX */
713
714 #ifdef DEBUG
715       fprintf(stdout,_("Done\n"));  
716 #endif
717
718 #ifndef UCLINUX
719       if (CurrentConnectionType==GCT_Infrared ||
720           CurrentConnectionType==GCT_Tekram)      {
721         device_changespeed(115200);    
722       }
723 #endif /* UCLINUX */
724
725       N6110_SendStatusRequest();
726     
727       usleep(100);
728
729       if (N6110_SendIDFrame()!=GE_NONE) return GE_TIMEOUT;
730     
731       /* N51xx/61xx have something called authentication.
732          After making it phone display "Accessory connected"
733          and probably give access to some function (I'm not too sure about it !)
734          Anyway, I make it now for N51xx/61xx */
735       if (GetModelFeature (FN_AUTHENTICATION)!=0) {
736         if (N6110_Authentication()!=GE_NONE) return GE_TIMEOUT;
737       } else {        /* No authentication */
738         if (N6110_SendIMEIFrame()!=GE_NONE) return GE_TIMEOUT;    
739
740         if (N6110_SendHWFrame()!=GE_NONE) return GE_TIMEOUT;    
741       }
742       
743       break;
744     default:
745 #ifdef DEBUG
746       fprintf(stdout,_("Unknown connection type in n6110.c!\n"));
747 #endif
748       break;
749   }
750
751   return (GE_NONE);
752 }
753
754 /* This function translates GMT_MemoryType to N6110_MEMORY_xx */
755 int N6110_GetMemoryType(GSM_MemoryType memory_type)
756 {
757
758   int result;
759
760   switch (memory_type) {
761
762      case GMT_MT: result = N6110_MEMORY_MT; break;
763      case GMT_ME: result = N6110_MEMORY_ME; break;
764      case GMT_SM: result = N6110_MEMORY_SM; break;
765      case GMT_FD: result = N6110_MEMORY_FD; break;
766      case GMT_ON: result = N6110_MEMORY_ON; break;
767      case GMT_EN: result = N6110_MEMORY_EN; break;
768      case GMT_DC: result = N6110_MEMORY_DC; break;
769      case GMT_RC: result = N6110_MEMORY_RC; break;
770      case GMT_MC: result = N6110_MEMORY_MC; break;
771      default    : result = N6110_MEMORY_XX;
772
773    }
774
775    return (result);
776 }
777
778 #ifndef UCLINUX
779
780 void N6110_ReplyCallDivert(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
781
782   switch (MessageBuffer[3]) {
783
784   case 0x02:
785
786 #ifdef DEBUG
787     fprintf(stdout, _("Message: Call divert status received\n"));
788     fprintf(stdout, _("   Divert type: "));
789     switch (MessageBuffer[6]) {
790       case 0x43: fprintf(stdout, _("when busy"));break;
791       case 0x3d: fprintf(stdout, _("when not answered"));break;
792       case 0x3e: fprintf(stdout, _("when phone off or no coverage"));break;
793       case 0x15: fprintf(stdout, _("all types of diverts"));break; //?
794       case 0x02: fprintf(stdout, _("all types of diverts"));break; //?
795       default:   fprintf(stdout, _("unknown %i"),MessageBuffer[6]);break;
796     }
797     fprintf(stdout, _("\n   Calls type : "));
798     if (MessageBuffer[6]==0x02)
799       fprintf(stdout, _("voice, fax & data")); //?
800     else {
801       switch (MessageBuffer[8]) {
802         case 0x0b: fprintf(stdout, _("voice"));break;
803         case 0x0d: fprintf(stdout, _("fax"));break;
804         case 0x19: fprintf(stdout, _("data"));break;
805         default:   fprintf(stdout, _("unknown %i"),MessageBuffer[8]);break;
806       }
807     }
808     fprintf(stdout, _("\n"));     
809     if (MessageBuffer[10]==0x01) {
810       fprintf(stdout, _("   Status     : active\n"));
811       fprintf(stdout, _("   Timeout    : %i seconds\n"),MessageBuffer[45]);
812       fprintf(stdout, _("   Number     : %s\n"),GSM_UnpackSemiOctetNumber(MessageBuffer+12,true));
813     } else {
814       fprintf(stdout, _("   Status     : deactivated\n"));     
815     }
816 #endif /* DEBUG */
817  
818     switch (MessageBuffer[6]) {
819       case 0x43: CurrentCallDivert->DType=GSM_CDV_Busy;break;
820       case 0x3d: CurrentCallDivert->DType=GSM_CDV_NoAnswer;break;
821       case 0x3e: CurrentCallDivert->DType=GSM_CDV_OutOfReach;break;
822       case 0x15: CurrentCallDivert->DType=GSM_CDV_AllTypes;break; //?
823       case 0x02: CurrentCallDivert->DType=GSM_CDV_AllTypes;break; //?
824     }
825
826     if (MessageBuffer[6]==0x02) //?
827       CurrentCallDivert->CType=GSM_CDV_AllCalls;
828     else {
829       switch (MessageBuffer[8]) {
830         case 0x0b: CurrentCallDivert->CType=GSM_CDV_VoiceCalls;break;
831         case 0x0d: CurrentCallDivert->CType=GSM_CDV_FaxCalls;  break;
832         case 0x19: CurrentCallDivert->CType=GSM_CDV_DataCalls; break;
833       }
834     }
835
836     if (MessageBuffer[10]==0x01) {
837       CurrentCallDivert->Enabled=true;
838       CurrentCallDivert->Timeout=MessageBuffer[45];
839       strcpy(CurrentCallDivert->Number,GSM_UnpackSemiOctetNumber(MessageBuffer+12,true));
840     } else {
841       CurrentCallDivert->Enabled=false;
842     }
843
844     CurrentCallDivertError=GE_NONE;
845     break;
846
847   case 0x03:
848 #ifdef DEBUG
849     fprintf(stdout, _("Message: Call divert status receiving error ?\n"));
850 #endif
851     CurrentCallDivertError=GE_UNKNOWN;
852     break;
853   }
854 }
855
856 GSM_Error N6110_CallDivert(GSM_CallDivert *cd)
857 {
858   char req[55] = { N6110_FRAME_HEADER, 0x01,
859                                        0x00, /* operation */
860                                        0x00,
861                                        0x00, /* divert type */
862                                        0x00, /* call type */
863                                        0x00 };
864   GSM_Error error;
865
866   int length = 0x09;
867
868   switch (cd->Operation) {
869     case GSM_CDV_Register:
870     case GSM_CDV_Enable:
871       req[4] = 0x03;
872       req[8] = 0x01;
873       req[29]= GSM_PackSemiOctetNumber(cd->Number, req + 9, false);
874       req[52]= cd->Timeout;
875       length = 55;
876       break;
877     case GSM_CDV_Erasure:
878     case GSM_CDV_Disable:
879       req[4] = 0x04;
880       break;
881     case GSM_CDV_Query:
882       req[4] = 0x05;
883       break;
884     default:
885       return GE_NOTIMPLEMENTED;
886   }
887
888   switch (cd->DType) {
889     case GSM_CDV_AllTypes  : req[6] = 0x15; break;
890     case GSM_CDV_Busy      : req[6] = 0x43; break;
891     case GSM_CDV_NoAnswer  : req[6] = 0x3d; break;
892     case GSM_CDV_OutOfReach: req[6] = 0x3e; break;
893     default:                 return GE_NOTIMPLEMENTED;
894   }
895
896   if ((cd->DType == GSM_CDV_AllTypes) &&
897       (cd->CType == GSM_CDV_AllCalls))
898     req[6] = 0x02;
899
900   switch (cd->CType) {
901     case GSM_CDV_AllCalls  :                break;
902     case GSM_CDV_VoiceCalls: req[7] = 0x0b; break;
903     case GSM_CDV_FaxCalls  : req[7] = 0x0d; break;
904     case GSM_CDV_DataCalls : req[7] = 0x19; break;
905     default:                 return GE_NOTIMPLEMENTED;
906   }
907
908   CurrentCallDivert = cd;
909
910   error=NULL_SendMessageSequence
911     (100, &CurrentCallDivertError, length, 0x06, req);
912
913   CurrentCallDivert = NULL;
914
915   return error;
916 }
917
918 GSM_Error N6110_Tests()
919 {
920   unsigned char buffer[3]={0x00,0x01,0xcf};
921   unsigned char buffer3[8]={0x00,0x01,0xce,0x1d,0xfe,0x23,0x00,0x00};
922   
923   GSM_Error error;
924
925   error=N6110_EnableExtendedCommands(0x01);
926   if (error!=GE_NONE) return error;
927
928   //make almost all tests
929   Protocol->SendMessage(8, 0x40, buffer3);
930
931   while (GSM->Initialise(PortDevice, "50", CurrentConnectionType, CurrentRLP_RXCallback)!=GE_NONE) {};
932
933   sleep(2);
934
935   return NULL_SendMessageSequence
936     (200, &CurrentNetworkInfoError, 3, 0x40, buffer);  
937 }
938
939 void N6110_DisplayTestsInfo(u8 *MessageBuffer) {
940
941   int i;
942
943   CurrentNetworkInfoError=GE_NONE;
944
945   for (i=0;i<MessageBuffer[3];i++) {
946     switch (i) {
947       case 0: fprintf(stdout,_("Unknown(%i)              "),i);break;
948       case 1: fprintf(stdout,_("MCU ROM checksum        "));break;
949       case 2: fprintf(stdout,_("MCU RAM interface       "));break;
950       case 3: fprintf(stdout,_("MCU RAM component       "));break;
951       case 4: fprintf(stdout,_("MCU EEPROM interface    "));break;
952       case 5: fprintf(stdout,_("MCU EEPROM component    "));break;
953       case 6: fprintf(stdout,_("Real Time Clock battery "));break;
954       case 7: fprintf(stdout,_("CCONT interface         "));break;
955       case 8: fprintf(stdout,_("AD converter            "));break;
956       case 9: fprintf(stdout,_("SW Reset                "));break;
957       case 10:fprintf(stdout,_("Power Off               "));break;
958       case 11:fprintf(stdout,_("Security Data           "));break;
959       case 12:fprintf(stdout,_("EEPROM Tune checksum    "));break;
960       case 13:fprintf(stdout,_("PPM checksum            "));break;
961       case 14:fprintf(stdout,_("MCU download DSP        "));break;
962       case 15:fprintf(stdout,_("DSP alive               "));break;
963       case 16:fprintf(stdout,_("COBBA serial            "));break;
964       case 17:fprintf(stdout,_("COBBA paraller          "));break;
965       case 18:fprintf(stdout,_("EEPROM security checksum"));break;
966       case 19:fprintf(stdout,_("PPM validity            "));break;
967       case 20:fprintf(stdout,_("Warranty state          "));break;
968       case 21:fprintf(stdout,_("Simlock check           "));break;
969       case 22:fprintf(stdout,_("IMEI check?             "));break;//from PC-Locals.is OK?
970       default:fprintf(stdout,_("Unknown(%i)             "),i);break;
971     }
972     switch (MessageBuffer[4+i]) {
973       case 0:   fprintf(stdout,_(" : done, result OK"));break;
974       case 0xff:fprintf(stdout,_(" : not done, result unknown"));break;
975       case 254: fprintf(stdout,_(" : done, result NOT OK"));break;
976       default:  fprintf(stdout,_(" : result unknown(%i)"),MessageBuffer[4+i]);break;
977     }
978     fprintf(stdout,_("\n"));
979   }
980 }
981
982 void N6110_ReplySimlockInfo(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
983
984   int i, j;
985   
986   char uni[100];
987     
988 #ifdef DEBUG
989   fprintf(stdout, _("Message: Simlock info received\n"));
990
991   j=0;
992   for (i=0; i < 12; i++)
993   {
994     if (j<24) {
995       fprintf(stdout,_("%c"), ('0' + (MessageBuffer[9+i] >> 4)));
996       j++;
997     }
998     if (j==5 || j==15) fprintf(stdout, _("\n"));
999     if (j!=15) {
1000       if (j<24) {
1001         fprintf(stdout,_("%c"), ('0' + (MessageBuffer[9+i] & 0x0f)));
1002         j++;
1003       }
1004     } else j++;
1005     if (j==20 || j==24) fprintf(stdout, _("\n"));
1006   }
1007       
1008   if ((MessageBuffer[6] & 1) == 1) fprintf(stdout,_("lock 1 closed\n"));
1009   if ((MessageBuffer[6] & 2) == 2) fprintf(stdout,_("lock 2 closed\n"));
1010   if ((MessageBuffer[6] & 4) == 4) fprintf(stdout,_("lock 3 closed\n"));
1011   if ((MessageBuffer[6] & 8) == 8) fprintf(stdout,_("lock 4 closed\n"));
1012
1013   /* I'm not sure here at all */
1014   if ((MessageBuffer[5] & 1) == 1) fprintf(stdout,_("lock 1 - user\n"));
1015   if ((MessageBuffer[5] & 2) == 2) fprintf(stdout,_("lock 2 - user\n"));
1016   if ((MessageBuffer[5] & 4) == 4) fprintf(stdout,_("lock 3 - user\n"));
1017   if ((MessageBuffer[5] & 8) == 8) fprintf(stdout,_("lock 4 - user\n"));
1018
1019   fprintf(stdout,_("counter for lock1: %i\n"),MessageBuffer[21]);
1020   fprintf(stdout,_("counter for lock2: %i\n"),MessageBuffer[22]);
1021   fprintf(stdout,_("counter for lock3: %i\n"),MessageBuffer[23]);
1022   fprintf(stdout,_("counter for lock4: %i\n"),MessageBuffer[24]);
1023
1024 #endif
1025
1026   j=0;
1027   for (i=0; i < 12; i++)
1028   {
1029     if (j<24) {
1030       uni[j]='0' + (MessageBuffer[9+i] >> 4);
1031       j++;
1032     }
1033     if (j!=15) {
1034       if (j<24) {
1035         uni[j]='0' + (MessageBuffer[9+i] & 0x0f);
1036         j++;
1037       }
1038     } else j++;
1039   }
1040
1041   strncpy(CurrentSimLock->simlocks[0].data,uni,5);
1042   CurrentSimLock->simlocks[0].data[5]=0;
1043   strncpy(CurrentSimLock->simlocks[3].data,uni+5,10);
1044   CurrentSimLock->simlocks[3].data[10]=0;
1045   strncpy(CurrentSimLock->simlocks[1].data,uni+16,4);
1046   CurrentSimLock->simlocks[1].data[4]=0;
1047   strncpy(CurrentSimLock->simlocks[2].data,uni+20,4);
1048   CurrentSimLock->simlocks[2].data[4]=0;                                    
1049
1050   CurrentSimLock->simlocks[0].enabled=((MessageBuffer[6] & 1) == 1);
1051   CurrentSimLock->simlocks[1].enabled=((MessageBuffer[6] & 2) == 2);
1052   CurrentSimLock->simlocks[2].enabled=((MessageBuffer[6] & 4) == 4);
1053   CurrentSimLock->simlocks[3].enabled=((MessageBuffer[6] & 8) == 8);
1054
1055   CurrentSimLock->simlocks[0].factory=((MessageBuffer[5] & 1) != 1);
1056   CurrentSimLock->simlocks[1].factory=((MessageBuffer[5] & 2) != 2);
1057   CurrentSimLock->simlocks[2].factory=((MessageBuffer[5] & 4) != 4);
1058   CurrentSimLock->simlocks[3].factory=((MessageBuffer[5] & 8) != 8);
1059
1060   CurrentSimLock->simlocks[0].counter=MessageBuffer[21];
1061   CurrentSimLock->simlocks[1].counter=MessageBuffer[22];
1062   CurrentSimLock->simlocks[2].counter=MessageBuffer[23];
1063   CurrentSimLock->simlocks[3].counter=MessageBuffer[24];
1064
1065   CurrentSimlockInfoError=GE_NONE;
1066 }
1067
1068 GSM_Error N6110_SimlockInfo(GSM_AllSimlocks *siml)
1069 {
1070   GSM_Error error;
1071   unsigned char req[] = {0x00,0x01,0x8a,0x00};
1072   error=N6110_EnableExtendedCommands(0x01);
1073   if (error!=GE_NONE) return error;
1074
1075   CurrentSimLock=siml;
1076  
1077   return NULL_SendMessageSequence (50, &CurrentSimlockInfoError, 4, 0x40, req);  
1078 }
1079
1080 void N6110_ReplyResetPhoneSettings(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1081
1082 #ifdef DEBUG
1083   fprintf(stdout, _("Message: Resetting phone settings\n"));
1084 #endif /* DEBUG */
1085
1086   CurrentResetPhoneSettingsError=GE_NONE;
1087 }
1088
1089 GSM_Error N6110_ResetPhoneSettings()
1090 {
1091   GSM_Error error;
1092   unsigned char req[] = {0x00,0x01,0x65,0x08,0x00};  
1093   error=N6110_EnableExtendedCommands(0x01);
1094   if (error!=GE_NONE) return error;
1095
1096   return NULL_SendMessageSequence
1097     (50, &CurrentResetPhoneSettingsError, 5, 0x40, req);  
1098 }
1099
1100 #endif /* UCLINUX */
1101
1102 GSM_Error N6110_GetManufacturer(char *manufacturer)
1103 {
1104         strcpy (manufacturer, "Nokia");
1105         return (GE_NONE);
1106 }
1107
1108 #ifndef UCLINUX
1109
1110 GSM_Error N6110_GetVoiceMailbox ( GSM_PhonebookEntry *entry)
1111 {
1112   unsigned char req[] = {N6110_FRAME_HEADER, 0x01, 0x00, 0x00, 0x00};
1113
1114   GSM_Error error;
1115   
1116   CurrentPhonebookEntry = entry;
1117
1118   req[4] = N6110_MEMORY_VOICE;
1119   req[5] = 0x00; /* Location - isn't important, but... */
1120
1121   error=NULL_SendMessageSequence
1122     (20, &CurrentPhonebookError, 7, 0x03, req);
1123     
1124   CurrentPhonebookEntry = NULL;
1125   
1126   return error;
1127 }
1128
1129 void N6110_ReplyGetOperatorName(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1130
1131   int i, count;
1132   
1133   GSM_Bitmap NullBitmap;
1134
1135   DecodeNetworkCode(MessageBuffer+5, NullBitmap.netcode);
1136   
1137   count=8;
1138
1139 #ifdef DEBUG
1140   fprintf(stdout, _("Message: Info about downloaded operator name received: %s network (for gnokii \"%s\", for phone \""),
1141           NullBitmap.netcode,
1142           GSM_GetNetworkName(NullBitmap.netcode));      
1143 #endif
1144       
1145   i=count;
1146   while (MessageBuffer[count]!=0) {
1147 #ifdef DEBUG
1148     fprintf(stdout,_("%c"),MessageBuffer[count]);
1149 #endif
1150     count++;
1151   }
1152       
1153  strcpy(CurrentGetOperatorNameNetwork->Code, NullBitmap.netcode);
1154  strncpy(CurrentGetOperatorNameNetwork->Name, MessageBuffer+i,count-i+1);
1155
1156 #ifdef DEBUG
1157   fprintf(stdout,_("\")\n"));
1158 #endif
1159           
1160   CurrentGetOperatorNameError=GE_NONE;
1161 }
1162
1163 GSM_Error N6110_GetOperatorName (GSM_Network *operator)
1164 {
1165   unsigned char req[] = { 0x00,0x01,0x8c,0x00};
1166
1167   GSM_Error error;
1168
1169   error=N6110_EnableExtendedCommands(0x01);
1170   if (error!=GE_NONE) return error;
1171
1172   CurrentGetOperatorNameNetwork = operator;
1173
1174   error=NULL_SendMessageSequence
1175     (20, &CurrentGetOperatorNameError, 4, 0x40, req);
1176
1177   CurrentGetOperatorNameNetwork = NULL;
1178   
1179   return error;
1180 }
1181
1182 void N6110_ReplySetOperatorName(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1183     
1184 #ifdef DEBUG
1185   fprintf(stdout, _("Message: Downloaded operator name changed\n"));
1186 #endif    
1187
1188   CurrentSetOperatorNameError=GE_NONE;      
1189 }
1190
1191 GSM_Error N6110_SetOperatorName (GSM_Network *operator)
1192 {
1193   unsigned char req[256] = { 0x00,0x01,0x8b,0x00,
1194                              0x00,0x00, /* MCC */
1195                              0x00};     /* MNC */
1196
1197   GSM_Error error;
1198
1199   error=N6110_EnableExtendedCommands(0x01);
1200   if (error!=GE_NONE) return error;
1201
1202   EncodeNetworkCode(req+4,operator->Code);
1203
1204   strncpy(req+7,operator->Name,200);
1205     
1206   return NULL_SendMessageSequence
1207     (20, &CurrentSetOperatorNameError, 8+strlen(operator->Name), 0x40, req);
1208 }
1209
1210 #endif /* UCLINUX */
1211
1212 static void N6110_ReplyGetMemoryStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1213
1214   switch (MessageBuffer[3]) {
1215
1216   case 0x08:
1217
1218 #ifdef DEBUG
1219     fprintf(stdout, _("Message: Memory status received:\n"));
1220
1221     fprintf(stdout, _("   Memory Type: %s\n"), N6110_MemoryType_String[MessageBuffer[4]]);
1222     fprintf(stdout, _("   Used: %d\n"), MessageBuffer[6]);
1223     fprintf(stdout, _("   Free: %d\n"), MessageBuffer[5]);
1224 #endif /* DEBUG */
1225
1226     CurrentMemoryStatus->Used = MessageBuffer[6];
1227     CurrentMemoryStatus->Free = MessageBuffer[5];
1228     CurrentMemoryStatusError = GE_NONE;
1229
1230     break;
1231
1232   case 0x09:
1233
1234 #ifdef DEBUG
1235     switch (MessageBuffer[4]) {
1236       case 0x6f:
1237         fprintf(stdout, _("Message: Memory status error, phone is probably powered off.\n"));break;
1238       case 0x7d:
1239         fprintf(stdout, _("Message: Memory status error, memory type not supported by phone model.\n"));break;
1240       case 0x8d:
1241         fprintf(stdout, _("Message: Memory status error, waiting for security code.\n"));break;
1242       default:
1243         fprintf(stdout, _("Message: Unknown Memory status error, subtype (MessageBuffer[4]) = %02x\n"),MessageBuffer[4]);break;
1244     }
1245 #endif
1246
1247     switch (MessageBuffer[4]) {
1248       case 0x6f:CurrentMemoryStatusError = GE_TIMEOUT;break;
1249       case 0x7d:CurrentMemoryStatusError = GE_INTERNALERROR;break;
1250       case 0x8d:CurrentMemoryStatusError = GE_INVALIDSECURITYCODE;break;
1251       default:break;
1252     }
1253
1254     break;
1255
1256   }
1257 }
1258
1259 /* This function is used to get storage status from the phone. It currently
1260    supports two different memory areas - internal and SIM. */
1261 GSM_Error N6110_GetMemoryStatus(GSM_MemoryStatus *Status)
1262 {
1263   unsigned char req[] = { N6110_FRAME_HEADER,
1264                           0x07, /* MemoryStatus request */
1265                           0x00  /* MemoryType */
1266                         };
1267
1268   GSM_Error error;
1269   
1270   CurrentMemoryStatus = Status;
1271
1272   req[4] = N6110_GetMemoryType(Status->MemoryType);
1273
1274   error=NULL_SendMessageSequence
1275     (20, &CurrentMemoryStatusError, 5, 0x03, req);
1276
1277   CurrentMemoryStatus = NULL;
1278
1279   return error;
1280 }
1281
1282 #ifndef UCLINUX
1283
1284 void N6110_ReplyGetNetworkInfo(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1285
1286   GSM_NetworkInfo NullNetworkInfo;
1287   
1288   /* Make sure we are expecting NetworkInfo frame */
1289   if (CurrentNetworkInfo && CurrentNetworkInfoError == GE_BUSY) {
1290 #ifdef DEBUG
1291     fprintf(stdout, _("Message: Network informations:\n"));
1292 #endif
1293   } else {
1294 #ifdef DEBUG
1295     fprintf(stdout, _("Message: Network informations not requested, but received:\n"));
1296 #endif
1297   }
1298       
1299   sprintf(NullNetworkInfo.NetworkCode, "%x%x%x %x%x", MessageBuffer[14] & 0x0f, MessageBuffer[14] >>4, MessageBuffer[15] & 0x0f, MessageBuffer[16] & 0x0f, MessageBuffer[16] >>4);
1300
1301   sprintf(NullNetworkInfo.CellID, "%02x%02x", MessageBuffer[10], MessageBuffer[11]);
1302
1303   sprintf(NullNetworkInfo.LAC, "%02x%02x", MessageBuffer[12], MessageBuffer[13]);
1304
1305 #ifdef DEBUG
1306   fprintf(stdout, _("   CellID: %s\n"), NullNetworkInfo.CellID);
1307   fprintf(stdout, _("   LAC: %s\n"), NullNetworkInfo.LAC);
1308   fprintf(stdout, _("   Network code: %s\n"), NullNetworkInfo.NetworkCode);
1309   fprintf(stdout, _("   Network name: %s (%s)\n"),
1310                      GSM_GetNetworkName(NullNetworkInfo.NetworkCode),
1311                      GSM_GetCountryName(NullNetworkInfo.NetworkCode));
1312   fprintf(stdout, _("   Status: "));
1313
1314   switch (MessageBuffer[8]) {
1315     case 0x01: fprintf(stdout, _("home network selected")); break;
1316     case 0x02: fprintf(stdout, _("roaming network")); break;
1317     case 0x03: fprintf(stdout, _("requesting network")); break;
1318     case 0x04: fprintf(stdout, _("not registered in the network")); break;
1319     default: fprintf(stdout, _("unknown"));
1320   }
1321
1322   fprintf(stdout, "\n");
1323
1324   fprintf(stdout, _("   Network selection: %s\n"), MessageBuffer[9]==1?_("manual"):_("automatic"));
1325 #endif /* DEBUG */
1326
1327   /* Make sure we are expecting NetworkInfo frame */
1328   if (CurrentNetworkInfo && CurrentNetworkInfoError == GE_BUSY)
1329     *CurrentNetworkInfo=NullNetworkInfo;
1330
1331   CurrentNetworkInfoError = GE_NONE;      
1332 }
1333
1334 GSM_Error N6110_GetNetworkInfo(GSM_NetworkInfo *NetworkInfo)
1335 {
1336   unsigned char req[] = { N6110_FRAME_HEADER,
1337                           0x70
1338                         };
1339
1340   GSM_Error error;
1341   
1342   CurrentNetworkInfo = NetworkInfo;
1343   
1344   error=NULL_SendMessageSequence
1345     (20, &CurrentNetworkInfoError, 4, 0x0a, req);
1346
1347   CurrentNetworkInfo = NULL;
1348
1349   return error;
1350 }
1351
1352 void N6110_ReplyGetProductProfileSetting(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1353
1354   int i;
1355   
1356 #ifdef DEBUG
1357   fprintf(stdout, _("Message: Product Profile Settings received -"));
1358   for (i=0;i<4;i++) fprintf(stdout, _(" %02x"),MessageBuffer[3+i]);
1359   fprintf(stdout, _("\n"));  
1360 #endif
1361
1362   for (i=0;i<4;i++) CurrentPPS[i]=MessageBuffer[3+i];
1363
1364   CurrentProductProfileSettingsError=GE_NONE;      
1365 }
1366
1367 GSM_Error N6110_GetProductProfileSetting (GSM_PPS *PPS)
1368 {
1369   unsigned char req[] = { 0x00, 0x01,0x6a };
1370   
1371   int i,j;
1372
1373   GSM_Error error;
1374
1375   error=N6110_EnableExtendedCommands(0x01);
1376   if (error!=GE_NONE) return error;
1377
1378   error=NULL_SendMessageSequence
1379     (20, &CurrentProductProfileSettingsError, 3, 0x40, req);
1380   if (error!=GE_NONE) return error;    
1381   
1382   switch (PPS->Name) {
1383     case PPS_ALS      : PPS->bool_value=(CurrentPPS[1]&32); break;
1384     case PPS_GamesMenu: PPS->bool_value=(CurrentPPS[3]&64); break;
1385     case PPS_HRData   : PPS->bool_value=(CurrentPPS[0]&64); break;
1386     case PPS_14400Data: PPS->bool_value=(CurrentPPS[0]&128);break;
1387     case PPS_EFR      : PPS->int_value =(CurrentPPS[0]&1)    +(CurrentPPS[0]&2);    break;
1388     case PPS_FR       : PPS->int_value =(CurrentPPS[0]&16)/16+(CurrentPPS[0]&32)/16;break;
1389     case PPS_HR       : PPS->int_value =(CurrentPPS[0]&4)/4  +(CurrentPPS[0]&8)/4;  break;
1390     case PPS_VibraMenu: PPS->bool_value=(CurrentPPS[4]&64); break;
1391     case PPS_LCDContrast:
1392          PPS->int_value=0;
1393          j=1;
1394          for (i=0;i<5;i++) {
1395            if (CurrentPPS[3]&j) PPS->int_value=PPS->int_value+j;
1396            j=j*2;
1397          }
1398          PPS->int_value=PPS->int_value*100/32;
1399          break;
1400
1401   }
1402   
1403   return (GE_NONE);
1404 }
1405
1406 void N6110_ReplySetProductProfileSetting(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1407
1408 #ifdef DEBUG
1409   int i;
1410   
1411   fprintf(stdout, _("Message: Product Profile Settings set to"));
1412   for (i=0;i<4;i++) fprintf(stdout, _(" %02x"),CurrentPPS[i]);
1413   fprintf(stdout, _("\n"));  
1414 #endif
1415      
1416   CurrentProductProfileSettingsError=GE_NONE;     
1417 }
1418
1419 GSM_Error N6110_SetProductProfileSetting (GSM_PPS *PPS)
1420 {
1421   unsigned char req[] = { 0x00, 0x01,0x6b, 
1422                           0x00, 0x00, 0x00, 0x00 }; /* bytes with Product Profile Setings */
1423   unsigned char settings[32];
1424   
1425   GSM_PPS OldPPS;
1426   
1427   int i,j,z;
1428   
1429   GSM_Error error;
1430
1431   error=N6110_EnableExtendedCommands(0x01);
1432   if (error!=GE_NONE) return error;
1433   
1434   OldPPS.Name=PPS_ALS;
1435   error=N6110_GetProductProfileSetting(&OldPPS);
1436   if (error!=GE_NONE) return error;
1437   
1438   j=128;z=0;
1439   for (i=0;i<32;i++) {
1440     if (CurrentPPS[z]&j)
1441       settings[i]='1';
1442     else
1443       settings[i]='0';    
1444     if (j==1) {
1445       j=128;
1446       z++;
1447     } else j=j/2;
1448   }
1449   
1450 #ifdef DEBUG
1451   fprintf(stdout,_("Current settings: "));
1452   for (i=0;i<32;i++) {
1453     fprintf(stdout,_("%c"),settings[i]);    
1454   }
1455   fprintf(stdout,_("\n"));
1456 #endif
1457
1458   switch (PPS->Name) {
1459     case PPS_ALS      :settings[10]=PPS->bool_value?'1':'0';break;
1460     case PPS_HRData   :settings[ 5]=PPS->bool_value?'1':'0';break;
1461     case PPS_14400Data:settings[ 6]=PPS->bool_value?'1':'0';break;
1462     default           :break;
1463   }
1464     
1465   j=128;z=0;
1466   for (i=0;i<32;i++) {
1467     if (settings[i]=='1') req[z+3]=req[z+3]+j;
1468     if (j==1) {
1469       j=128;
1470       z++;
1471     } else j=j/2;
1472   }  
1473
1474 #ifdef DEBUG
1475   fprintf(stdout,_("Current settings: "));
1476   for (i=0;i<4;i++) {
1477     fprintf(stdout,_("%i "),req[i+3]);    
1478   }
1479   fprintf(stdout,_("\n"));
1480 #endif
1481
1482   for (i=0;i<4;i++) {
1483    CurrentPPS[i]=req[i+3];    
1484   }
1485
1486   return NULL_SendMessageSequence
1487     (20, &CurrentProductProfileSettingsError, 7, 0x40, req);
1488 }
1489
1490 void N6110_ReplyPressKey(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1491
1492     if (MessageBuffer[4]==CurrentPressKeyEvent) CurrentPressKeyError=GE_NONE;
1493                                            else CurrentPressKeyError=GE_UNKNOWN; /* MessageBuffer[4] = 0x05 */
1494 #ifdef DEBUG
1495     fprintf(stdout, _("Message: Result of key "));
1496     switch (MessageBuffer[4])
1497     {
1498       case PRESSPHONEKEY:   fprintf(stdout, _("press OK\n"));break;
1499       case RELEASEPHONEKEY: fprintf(stdout, _("release OK\n"));break;
1500       default:              fprintf(stdout, _("press or release - error\n"));break;
1501     }
1502 #endif /* DEBUG */
1503 }
1504
1505 GSM_Error N6110_PressKey(int key, int event)
1506 {
1507   unsigned char req[] = {N6110_FRAME_HEADER, 0x42, 0x01, 0x00, 0x01};
1508   
1509   req[4]=event; /* if we press or release key */
1510   req[5]=key;
1511   
1512   CurrentPressKeyEvent=event;
1513   
1514   return NULL_SendMessageSequence
1515     (10, &CurrentPressKeyError, 7, 0x0c, req);
1516 }
1517
1518 void N6110_ReplyDisplayOutput(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1519
1520   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
1521   char model[64];
1522
1523   int i, j;
1524
1525   char uni[100];
1526     
1527   switch(MessageBuffer[3]) {
1528
1529   /* Phone sends displayed texts */
1530   case 0x50:
1531     NewX=MessageBuffer[6];
1532     NewY=MessageBuffer[5];
1533
1534     DecodeUnicode (uni, MessageBuffer+8, MessageBuffer[7]);
1535
1536 #ifdef DEBUG
1537     fprintf(stdout, _("New displayed text (%i %i): \"%s\"\n"),NewX,NewY,uni);      
1538 #endif /* DEBUG */
1539
1540     while (N6110_GetModel(model)  != GE_NONE)
1541       sleep(1);
1542
1543     /* With these rules it works almost excellent with my N5110 */
1544     /* I don't have general rule :-(, that's why you must experiment */
1545     /* with your phone. Nokia could make it better. MW */
1546     /* It's almost OK for N5110*/
1547     /* FIX ME: it will be the same for N5130 and 3210 too*/
1548     if (!strcmp(model,"NSE-1"))
1549     {
1550       /* OldX==1000 means - it's first time */
1551       if (OldX==1000) {
1552       
1553         /* Clean table */
1554         for (i=0;i<5+1;i++) {
1555           for (j=0;j<27+1;j++) {PhoneScreen[i][j]=' ';}
1556       }
1557       OldX=0;
1558     }
1559
1560     if ((OldX==0 && OldY==31 && NewX==29 && NewY==46) ||
1561         (OldX==0 && OldY==13 && NewX==23 && NewY==46)) {
1562       /* Clean the line with current text */
1563       for (j=0;j<27+1;j++) {PhoneScreen[NewY/(47/5)][j]=' ';}
1564       
1565       /* Inserts text into table */
1566       for (i=0; i<MessageBuffer[7];i++) {       
1567         PhoneScreen[NewY/(47/5)][NewX/(84/27)+i]=uni[i];
1568       }
1569
1570     }
1571
1572     if ((OldX==0 && OldY==21 && NewX==0 && NewY==10) ||
1573         (OldX==0 && OldY==10 && NewX==35 && NewY==46)) {
1574     } else {
1575       if ((OldX!=0 && NewX==0 && NewY!=6) ||
1576           (OldX==0 && NewX!=0 && OldY!=13 && OldY!=22) ||
1577           (OldX==0 && NewX==0 && NewY<OldY && (NewY!=13 || OldY!=26)) ||
1578           (OldY==5 && NewY!=5) ||
1579           (OldX==0 && OldY==13 && NewX==23 && NewY==46)) {
1580
1581         /* Writes "old" screen */
1582         for (i=0;i<5+1;i++) {
1583           for (j=0;j<27+1;j++) {fprintf(stdout,_("%c"),PhoneScreen[i][j]);}
1584             fprintf(stdout,_("\n"));
1585           }
1586         
1587           /* Clean table */
1588           for (i=0;i<5+1;i++) {
1589             for (j=0;j<27+1;j++) {PhoneScreen[i][j]=' ';}
1590           }
1591         }
1592       }
1593       
1594       /* Clean the line with current text */
1595       for (j=0;j<27+1;j++) {PhoneScreen[NewY/(47/5)][j]=' ';}
1596       
1597       /* Inserts text into table */
1598       for (i=0; i<MessageBuffer[7];i++) {       
1599         PhoneScreen[NewY/(47/5)][NewX/(84/27)+i]=uni[i];
1600       }
1601       
1602       OldY=NewY;
1603       OldX=NewX;
1604     } else {
1605 #ifndef DEBUG
1606       fprintf(stdout, _("%s\n"),uni);      
1607 #endif
1608     }
1609
1610     break;
1611  
1612   case 0x54:
1613       
1614     if (MessageBuffer[4]==1)
1615     {
1616       
1617 #ifdef DEBUG
1618       fprintf(stdout, _("Display output successfully disabled/enabled.\n"));
1619 #endif /* DEBUG */
1620
1621       CurrentDisplayOutputError=GE_NONE;
1622     }
1623        
1624     break;
1625   }
1626 }
1627
1628 GSM_Error SetDisplayOutput(unsigned char state)
1629 {
1630   unsigned char req[] = { N6110_FRAME_HEADER,
1631                           0x53, 0x00};
1632
1633   req[4]=state;
1634   
1635   return NULL_SendMessageSequence
1636     (30, &CurrentDisplayOutputError, 5, 0x0d, req);
1637 }
1638
1639 GSM_Error N6110_EnableDisplayOutput()
1640 {
1641   return SetDisplayOutput(0x01);
1642 }
1643  
1644 GSM_Error N6110_DisableDisplayOutput()
1645 {
1646   return SetDisplayOutput(0x02);
1647 }
1648
1649 /* If it is interesting for somebody: we can use 0x40 msg for it
1650    and it will work for all phones. See n6110.txt for details */
1651 GSM_Error N6110_AnswerCall(char s)
1652 {
1653         unsigned char req0[] = { N6110_FRAME_HEADER, 0x42,0x05,0x01,0x07,                                0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
1654                             0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80};
1655         unsigned char req[] = { N6110_FRAME_HEADER, 0x06, 0x00, 0x00};
1656
1657         req[4]=s;
1658
1659 #ifdef DEBUG
1660         fprintf(stdout,_("Answering call %d\n\r"),s);
1661 #endif
1662
1663         Protocol->SendMessage(sizeof(req0), 0x01, req0);
1664         sleep(1);
1665
1666         return NULL_SendMessageSequence
1667                 (20, &CurrentMagicError, sizeof(req) , 0x01, req);
1668 }
1669
1670 void N6110_ReplyGetProfile(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1671
1672   switch (MessageBuffer[3]) {
1673
1674   /* Profile feature */
1675   case 0x14:   
1676
1677     switch(GetModelFeature (FN_PROFILES)) {
1678       case F_PROF33:
1679         switch (MessageBuffer[6]) {
1680           case 0x00: CurrentProfile->KeypadTone  = MessageBuffer[8]; break;
1681           case 0x01: CurrentProfile->CallAlert   = MessageBuffer[8]; break;
1682           case 0x02: CurrentProfile->Ringtone    = MessageBuffer[8]; break;
1683           case 0x03: CurrentProfile->Volume      = MessageBuffer[8]; break;
1684           case 0x04: CurrentProfile->MessageTone = MessageBuffer[8]; break;
1685           case 0x05: CurrentProfile->Vibration   = MessageBuffer[8]; break;
1686           case 0x06: CurrentProfile->WarningTone = MessageBuffer[8]; break;
1687           case 0x07: CurrentProfile->ScreenSaver = MessageBuffer[8]; break;       
1688           default:
1689 #ifdef DEBUG
1690             fprintf(stdout,_("feature %i = value %i\n\n"),MessageBuffer[6],MessageBuffer[8]);
1691 #endif
1692             break;
1693         }
1694         break;
1695       default:
1696         switch (MessageBuffer[6]) {
1697           case 0x00: CurrentProfile->KeypadTone      = MessageBuffer[8];break;
1698           case 0x01: CurrentProfile->Lights          = MessageBuffer[8];break;
1699           case 0x02: CurrentProfile->CallAlert       = MessageBuffer[8];break;
1700           case 0x03: CurrentProfile->Ringtone        = MessageBuffer[8];break;
1701           case 0x04: CurrentProfile->Volume          = MessageBuffer[8];break;
1702           case 0x05: CurrentProfile->MessageTone     = MessageBuffer[8];break;
1703           case 0x06: CurrentProfile->Vibration       = MessageBuffer[8];break;
1704           case 0x07: CurrentProfile->WarningTone     = MessageBuffer[8];break;
1705           case 0x08: CurrentProfile->CallerGroups    = MessageBuffer[8];break;
1706           case 0x09: CurrentProfile->AutomaticAnswer = MessageBuffer[8];break;
1707           default:
1708 #ifdef DEBUG
1709             fprintf(stdout,_("feature %i = value %i\n\n"),MessageBuffer[6],MessageBuffer[8]);
1710 #endif
1711             break;
1712         }
1713         break;
1714     }
1715
1716     CurrentProfileError = GE_NONE;
1717     break;
1718
1719   /* Incoming profile name */
1720   case 0x1b:   
1721
1722     if (MessageBuffer[9] == 0x00) {
1723       CurrentProfile->DefaultName=MessageBuffer[8];
1724     } else {
1725       CurrentProfile->DefaultName=-1;      
1726         
1727       /* Here name is in Unicode */
1728       if (GetModelFeature (FN_PROFILES)==F_PROF33) {
1729         DecodeUnicode (CurrentProfile->Name, MessageBuffer+10, MessageBuffer[9]/2);
1730       } else {
1731         /* ...here not */
1732         sprintf(CurrentProfile->Name, MessageBuffer + 10, MessageBuffer[9]);
1733         CurrentProfile->Name[MessageBuffer[9]] = '\0';
1734       }
1735     }
1736
1737     CurrentProfileError = GE_NONE;
1738     break;
1739
1740   }
1741 }
1742
1743 /* Needs SIM card with PIN in phone */
1744 GSM_Error N6110_GetProfile(GSM_Profile *Profile)
1745 {
1746   int i;
1747   
1748   unsigned char name_req[] = { N6110_FRAME_HEADER, 0x1a, 0x00};
1749   unsigned char feat_req[] = { N6110_FRAME_HEADER, 0x13, 0x01, 0x00, 0x00};
1750
1751   GSM_Error error;
1752   
1753   CurrentProfile = Profile;
1754
1755   /* When after sending all frames feature==253, it means, that it is not
1756      supported */
1757   CurrentProfile->KeypadTone=253;
1758   CurrentProfile->Lights=253;    
1759   CurrentProfile->CallAlert=253; 
1760   CurrentProfile->Ringtone=253;  
1761   CurrentProfile->Volume=253;    
1762   CurrentProfile->MessageTone=253;
1763   CurrentProfile->WarningTone=253;
1764   CurrentProfile->Vibration=253;  
1765   CurrentProfile->CallerGroups=253;
1766   CurrentProfile->ScreenSaver=253; 
1767   CurrentProfile->AutomaticAnswer=253;
1768
1769   name_req[4] = Profile->Number;
1770
1771   error=NULL_SendMessageSequence
1772     (20, &CurrentProfileError, 5, 0x05, name_req);
1773   if (error!=GE_NONE) return error;
1774
1775   for (i = 0x00; i <= 0x09; i++) {
1776
1777     feat_req[5] = Profile->Number;
1778     
1779     feat_req[6] = i;
1780
1781     error=NULL_SendMessageSequence
1782       (20, &CurrentProfileError, 7, 0x05, feat_req);
1783     if (error!=GE_NONE) return error;
1784   }
1785
1786   if (Profile->DefaultName > -1)
1787   {
1788     switch(GetModelFeature (FN_PROFILES)) {
1789       case F_PROF33:
1790         switch (Profile->DefaultName) {
1791           case 0x00: sprintf(Profile->Name, "General");break;
1792           case 0x01: sprintf(Profile->Name, "Silent");break;
1793           case 0x02: sprintf(Profile->Name, "Descreet");break;
1794           case 0x03: sprintf(Profile->Name, "Loud");break;
1795           case 0x04: sprintf(Profile->Name, "My style");break;
1796           case 0x05: Profile->Name[0]=0;break;
1797           default  : sprintf(Profile->Name, "Unknown (%i)", Profile->DefaultName);break;
1798         }
1799         break;
1800       case F_PROF51:
1801         switch (Profile->DefaultName) {
1802           case 0x00: sprintf(Profile->Name, "Personal");break;
1803           case 0x01: sprintf(Profile->Name, "Car");break;
1804           case 0x02: sprintf(Profile->Name, "Headset");break;
1805           default  : sprintf(Profile->Name, "Unknown (%i)", Profile->DefaultName);break;
1806         }
1807         break;
1808       case F_PROF61:
1809         switch (Profile->DefaultName) {
1810           case 0x00: sprintf(Profile->Name, "General");break;
1811           case 0x01: sprintf(Profile->Name, "Silent");break;
1812           case 0x02: sprintf(Profile->Name, "Meeting");break;
1813           case 0x03: sprintf(Profile->Name, "Outdoor");break;
1814           case 0x04: sprintf(Profile->Name, "Pager");break;
1815           case 0x05: sprintf(Profile->Name, "Car");break;
1816           case 0x06: sprintf(Profile->Name, "Headset");break;
1817           default  : sprintf(Profile->Name, "Unknown (%i)", Profile->DefaultName);break;
1818         }
1819         break;
1820     }
1821   }
1822   
1823   return (GE_NONE);
1824
1825 }
1826
1827 void N6110_ReplySetProfile(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1828
1829   switch (MessageBuffer[3]) {
1830
1831   /* Profile feature change result */
1832   case 0x11:   
1833 #ifdef DEBUG
1834     fprintf(stdout, _("Message: Profile feature change result.\n"));
1835 #endif /* DEBUG */
1836     CurrentProfileError = GE_NONE;
1837     break;
1838
1839   /* Profile name set result */
1840   case 0x1d:   
1841 #ifdef DEBUG
1842     fprintf(stdout, _("Message: Profile name change result.\n"));
1843 #endif /* DEBUG */
1844     CurrentProfileError = GE_NONE;
1845     break;
1846
1847   }
1848 }
1849
1850 GSM_Error N6110_SetProfileFeature(u8 profile, u8 feature, u8 value)
1851 {
1852   unsigned char feat_req[] = { N6110_FRAME_HEADER, 0x10, 0x01,
1853                                0x00, 0x00, 0x00};
1854
1855   feat_req[5]=profile;
1856   feat_req[6]=feature;
1857   feat_req[7]=value;
1858
1859   return NULL_SendMessageSequence
1860     (20, &CurrentProfileError, 8, 0x05, feat_req);
1861 }
1862
1863 GSM_Error N6110_SetProfile(GSM_Profile *Profile)
1864 {
1865   int i,value;
1866
1867   unsigned char name_req[40] = { N6110_FRAME_HEADER, 0x1c, 0x01, 0x03,
1868                                  0x00, 0x00, 0x00};
1869
1870   GSM_Error error;
1871   
1872   name_req[7] = Profile->Number;
1873   name_req[8] = strlen(Profile->Name);
1874   name_req[6] = name_req[8] + 2;
1875
1876   for (i = 0; i < name_req[8]; i++)
1877     name_req[9 + i] = Profile->Name[i];
1878
1879   error=NULL_SendMessageSequence
1880     (20, &CurrentProfileError, name_req[8] + 9, 0x05, name_req);
1881   if (error!=GE_NONE) return error;
1882
1883   for (i = 0x00; i <= 0x09; i++) {
1884
1885     switch (i) {
1886       case 0x00: value = Profile->KeypadTone; break;
1887       case 0x01: value = Profile->Lights; break;
1888       case 0x02: value = Profile->CallAlert; break;
1889       case 0x03: value = Profile->Ringtone; break;
1890       case 0x04: value = Profile->Volume; break;
1891       case 0x05: value = Profile->MessageTone; break;
1892       case 0x06: value = Profile->Vibration; break;
1893       case 0x07: value = Profile->WarningTone; break;
1894       case 0x08: value = Profile->CallerGroups; break;
1895       case 0x09: value = Profile->AutomaticAnswer; break;
1896       default  : value = 0; break;
1897     }
1898
1899     error=N6110_SetProfileFeature(Profile->Number,i,value);
1900     if (error!=GE_NONE) return error;
1901   }
1902
1903   return (GE_NONE);
1904 }
1905
1906 bool N6110_SendRLPFrame(RLP_F96Frame *frame, bool out_dtx)
1907 {
1908   u8 req[60] = { 0x00, 0xd9 };
1909                 
1910   /* Discontinuos transmission (DTX).  See section 5.6 of GSM 04.22 version
1911      7.0.1. */
1912        
1913   if (out_dtx)
1914     req[1]=0x01;
1915
1916   memcpy(req+2, (u8 *) frame, 32);
1917
1918   return (Protocol->SendFrame(32, 0xf0, req));
1919 }
1920
1921 void N6110_ReplyGetCalendarNote(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1922
1923   int i, j;
1924
1925   u8 mychar1;
1926
1927   wchar_t wc;  
1928     
1929   switch (MessageBuffer[4]) {
1930
1931     case 0x01:
1932       
1933       CurrentCalendarNote->Type=MessageBuffer[8];
1934
1935       DecodeDateTime(MessageBuffer+9, &CurrentCalendarNote->Time);
1936
1937       DecodeDateTime(MessageBuffer+16, &CurrentCalendarNote->Alarm);
1938
1939       CurrentCalendarNote->Text[0]=0;
1940       
1941       if (GetModelFeature (FN_CALENDAR)==F_CAL33) {
1942         i=0;
1943         if (CurrentCalendarNote->Type == GCN_REMINDER) i=1; //first char is subset
1944         switch (MessageBuffer[24]) {
1945           case 3:
1946 #ifdef DEBUG
1947             fprintf(stdout,_("Subset 3 in reminder note !\n"));
1948 #endif
1949             while (i!=MessageBuffer[23]) {
1950               j=0;
1951               if (i!=MessageBuffer[23]-1) {
1952                 if (MessageBuffer[24+i]>=0xc2) {
1953                   DecodeWithUTF8Alphabet(MessageBuffer[24+i], MessageBuffer[24+i+1], &mychar1);
1954                   CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)+1]=0;
1955                   CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)]=mychar1;
1956                   j=-1;
1957                   i++;
1958                 }
1959               }
1960               if (j!=-1) {
1961                 CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)+1]=0;
1962                 CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)]=MessageBuffer[24+i];
1963               }
1964               i++;
1965             }
1966             break;
1967           case 2:
1968 #ifdef DEBUG
1969             fprintf(stdout,_("Subset 2 in reminder note !\n"));
1970 #endif
1971             while (i!=MessageBuffer[23]) {
1972               wc = MessageBuffer[24+i] | (0x00 << 8);
1973               CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)+1]=0;
1974               CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)]=
1975                       DecodeWithUnicodeAlphabet(wc);
1976               i++;
1977             }
1978             break;
1979           case 1:
1980 #ifdef DEBUG
1981             fprintf(stdout,_("Subset 1 in reminder note !\n"));
1982 #endif
1983             memcpy(CurrentCalendarNote->Text,MessageBuffer+24+i,MessageBuffer[23]-i);
1984             CurrentCalendarNote->Text[MessageBuffer[23]-i]=0;
1985             break;
1986           default:
1987 #ifdef DEBUG
1988             fprintf(stdout,_("Unknown subset in reminder note !\n"));
1989 #endif
1990             memcpy(CurrentCalendarNote->Text,MessageBuffer+24+i,MessageBuffer[23]-i);
1991             CurrentCalendarNote->Text[MessageBuffer[23]-i]=0;
1992             break;
1993         }
1994       } else {
1995         memcpy(CurrentCalendarNote->Text,MessageBuffer+24,MessageBuffer[23]);
1996         CurrentCalendarNote->Text[MessageBuffer[23]]=0;
1997       }
1998       
1999       if (CurrentCalendarNote->Type == GCN_CALL) {
2000         memcpy(CurrentCalendarNote->Phone,MessageBuffer+24+MessageBuffer[23]+1,MessageBuffer[24+MessageBuffer[23]]);
2001         CurrentCalendarNote->Phone[MessageBuffer[24+MessageBuffer[23]]]=0;
2002       }
2003
2004       CurrentCalendarNote->Recurrance=0;
2005
2006       CurrentCalendarNote->AlarmType=0;
2007
2008 #ifdef DEBUG
2009       fprintf(stdout, _("Message: Calendar note received.\n"));
2010
2011       fprintf(stdout, _("   Date: %d-%02d-%02d\n"), CurrentCalendarNote->Time.Year,
2012                                            CurrentCalendarNote->Time.Month,
2013                                            CurrentCalendarNote->Time.Day);
2014
2015       fprintf(stdout, _("   Time: %02d:%02d:%02d\n"), CurrentCalendarNote->Time.Hour,
2016                                            CurrentCalendarNote->Time.Minute,
2017                                            CurrentCalendarNote->Time.Second);
2018
2019       /* Some messages do not have alarm set up */
2020       if (CurrentCalendarNote->Alarm.Year != 0) {
2021         fprintf(stdout, _("   Alarm date: %d-%02d-%02d\n"), CurrentCalendarNote->Alarm.Year,
2022                                                  CurrentCalendarNote->Alarm.Month,
2023                                                  CurrentCalendarNote->Alarm.Day);
2024
2025         fprintf(stdout, _("   Alarm time: %02d:%02d:%02d\n"), CurrentCalendarNote->Alarm.Hour,
2026                                                  CurrentCalendarNote->Alarm.Minute,
2027                                                  CurrentCalendarNote->Alarm.Second);
2028       }
2029
2030       fprintf(stdout, _("   Type: %d\n"), CurrentCalendarNote->Type);
2031       fprintf(stdout, _("   Text: %s\n"), CurrentCalendarNote->Text);
2032
2033       if (CurrentCalendarNote->Type == GCN_CALL)
2034         fprintf(stdout, _("   Phone: %s\n"), CurrentCalendarNote->Phone);
2035 #endif /* DEBUG */
2036
2037       CurrentCalendarNoteError=GE_NONE;
2038       break;
2039
2040     case 0x93:
2041
2042 #ifdef DEBUG
2043       fprintf(stdout, _("Message: Calendar note not available\n"));
2044 #endif /* DEBUG */
2045
2046       CurrentCalendarNoteError=GE_INVALIDCALNOTELOCATION;
2047       break;
2048
2049     default:
2050
2051 #ifdef DEBUG
2052       fprintf(stdout, _("Message: Calendar note error\n"));
2053 #endif /* DEBUG */
2054
2055       CurrentCalendarNoteError=GE_INTERNALERROR;
2056       break;
2057
2058   }
2059 }
2060
2061 GSM_Error N6110_GetCalendarNote(GSM_CalendarNote *CalendarNote)
2062 {
2063
2064   unsigned char req[] = { N6110_FRAME_HEADER,
2065                           0x66, 0x00
2066                         };
2067   GSM_Error error;
2068
2069   req[4]=CalendarNote->Location;
2070
2071   CurrentCalendarNote = CalendarNote;
2072
2073   error=NULL_SendMessageSequence
2074     (20, &CurrentCalendarNoteError, 5, 0x13, req);
2075
2076   CurrentCalendarNote = NULL;
2077
2078   return error;
2079 }
2080
2081 void N6110_ReplyWriteCalendarNote(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2082
2083 #ifdef DEBUG
2084   switch(MessageBuffer[4]) {
2085     /* This message is also sent when the user enters the new entry on keypad */
2086     case 0x01:
2087       fprintf(stdout, _("Message: Calendar note write succesfull!\n"));break;      
2088     case 0x73:
2089       fprintf(stdout, _("Message: Calendar note write failed!\n"));break;
2090     case 0x7d:
2091       fprintf(stdout, _("Message: Calendar note write failed!\n"));break;
2092     default:
2093       fprintf(stdout, _("Unknown message of type 0x13 and subtype 0x65\n"));break;
2094   }
2095 #endif
2096
2097   switch(MessageBuffer[4]) {
2098     case 0x01: CurrentCalendarNoteError=GE_NONE; break;      
2099     case 0x73: CurrentCalendarNoteError=GE_INTERNALERROR; break;
2100     case 0x7d: CurrentCalendarNoteError=GE_INTERNALERROR; break;
2101     default  : AppendLogText("Unknown msg\n",false); break;
2102   }
2103 }
2104
2105 GSM_Error N6110_WriteCalendarNote(GSM_CalendarNote *CalendarNote)
2106 {
2107
2108   unsigned char req[200] = { N6110_FRAME_HEADER,
2109                              0x64, 0x01, 0x10,
2110                              0x00, /* Length of the rest of the frame. */
2111                              0x00, /* The type of calendar note */
2112                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2113                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2114                         };
2115
2116   typedef struct {
2117     char *model;
2118     unsigned char call;
2119     unsigned char meeting;
2120     unsigned char birthday;
2121     unsigned char reminder;
2122   } calendar_model_length;
2123   
2124   /* Length of entries */
2125   calendar_model_length calendar_lengths[] =
2126   {
2127     /*model,CallTo,Meeting,Birthday,Reminder*/
2128     {"NHM-5",0x24,0x24,0x24,0x24}, //Reminder from phone, other quesses
2129     {"NHM-6",0x24,0x24,0x24,0x24}, //Reminder from phone, other quesses
2130     {"NSE-3",0x1e,0x14,0x14,0x1e}, //from NCDS3 [HKEY_LOCAL_MACHINE\Software\Nokia\Data Suite\3.0\Calendar]
2131     {"NSM-1",0x1e,0x18,0x18,0x24}, //from NCDS3 
2132     {"NSK-3",0x1e,0x14,0x14,0x1e}, //from NCDS3 
2133     {"NSB-3",0x20,0x14,0x14,0x1e}, //from NCDS3
2134     {"",     0,   0,   0,   0   }  //end of table
2135   };
2136
2137   int i, j, current;
2138
2139   u8 mychar;
2140   
2141   u8 mychar1,mychar2;
2142   
2143   GSM_Error error;
2144   
2145   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
2146   char model[64];
2147
2148   req[7]=CalendarNote->Type;
2149
2150   EncodeDateTime(req+8, &CalendarNote->Time);
2151   req[14] = CalendarNote->Time.Timezone;
2152
2153   if (CalendarNote->Alarm.Year) {
2154     EncodeDateTime(req+15, &CalendarNote->Alarm);
2155     req[21] = CalendarNote->Alarm.Timezone;
2156   }
2157
2158   req[22]=strlen(CalendarNote->Text);
2159   
2160   current=23;
2161
2162   if (GetModelFeature (FN_CALENDAR)==F_CAL33 && CalendarNote->Type==GCN_REMINDER) {
2163     req[22]++;           // one additional char
2164     req[current++]=0x01; //we use now subset 1
2165   }
2166     
2167   for (i=0; i<strlen(CalendarNote->Text); i++) {
2168     j=0;
2169     mychar=CalendarNote->Text[i];
2170     if (GetModelFeature (FN_CALENDAR)==F_CAL33 && CalendarNote->Type==GCN_REMINDER) {
2171       if (EncodeWithUTF8Alphabet(mychar,&mychar1,&mychar2)) {
2172           req[current++]=mychar1;
2173           req[current++]=mychar2;
2174           req[23]=0x03; //use subset 3
2175           req[22]++;    // one additional char
2176           j=-1;
2177       }
2178     }
2179     if (j!=-1) {
2180       /* Enables/disables blinking */
2181       if (mychar=='~') req[current++]=0x01;
2182                   else req[current++]=mychar;
2183     }
2184   }
2185
2186   req[current++]=strlen(CalendarNote->Phone);
2187
2188   for (i=0; i<strlen(CalendarNote->Phone); i++)
2189     req[current++]=CalendarNote->Phone[i];
2190
2191   while (N6110_GetModel(model)  != GE_NONE)
2192     sleep(1);
2193
2194   /* Checking maximal length */
2195   i=0;
2196   while (strcmp(calendar_lengths[i].model,"")) {
2197     if (!strcmp(calendar_lengths[i].model,model)) {
2198       switch (CalendarNote->Type) {
2199         case GCN_REMINDER:if (req[22]>calendar_lengths[i].reminder) return GE_TOOLONG;break;
2200         case GCN_MEETING :if (req[22]>calendar_lengths[i].meeting)  return GE_TOOLONG;break;
2201         case GCN_BIRTHDAY:if (req[22]>calendar_lengths[i].birthday) return GE_TOOLONG;break;
2202         case GCN_CALL    :if (strlen(CalendarNote->Phone)>calendar_lengths[i].call) return GE_TOOLONG;break;
2203       }
2204       break;
2205     }
2206     i++;
2207   }
2208
2209   CurrentCalendarNote = CalendarNote;
2210
2211   error=NULL_SendMessageSequence
2212     (20, &CurrentCalendarNoteError, current, 0x13, req);
2213
2214   CurrentCalendarNote = NULL;
2215
2216   return error;
2217 }
2218
2219 void N6110_ReplyDeleteCalendarNote(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2220
2221 #ifdef DEBUG
2222   switch (MessageBuffer[4]) {
2223     /* This message is also sent when the user deletes an old entry on
2224        keypad or moves an old entry somewhere (there is also `write'
2225        message). */
2226     case 0x01:fprintf(stdout, _("Message: Calendar note deleted\n"));break;
2227     case 0x93:fprintf(stdout, _("Message: Calendar note can't be deleted\n"));break;
2228     default  :fprintf(stdout, _("Message: Calendar note deleting error\n"));break;
2229   }
2230 #endif
2231
2232   switch (MessageBuffer[4]) {
2233     case 0x01:CurrentCalendarNoteError=GE_NONE;break;
2234     case 0x93:CurrentCalendarNoteError=GE_INVALIDCALNOTELOCATION;break;
2235     default  :CurrentCalendarNoteError=GE_INTERNALERROR;break;
2236   }
2237 }
2238
2239 GSM_Error N6110_DeleteCalendarNote(GSM_CalendarNote *CalendarNote)
2240 {
2241
2242   unsigned char req[] = { N6110_FRAME_HEADER,
2243                           0x68, 0x00
2244                         };
2245
2246   req[4]=CalendarNote->Location;
2247
2248   return NULL_SendMessageSequence (20, &CurrentCalendarNoteError, 5, 0x13, req);
2249 }
2250
2251 #endif /* UCLINUX */
2252
2253 static void N6110_ReplyRFBatteryLevel(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2254
2255 #ifdef DEBUG
2256     fprintf(stdout, _("Message: Phone status received:\n"));
2257     fprintf(stdout, _("   Mode: "));
2258
2259     switch (MessageBuffer[4]) {
2260
2261       case 0x01:
2262
2263         fprintf(stdout, _("registered within the network\n"));
2264         break;
2265               
2266       /* I was really amazing why is there a hole in the type of 0x02, now I
2267          know... */
2268       case 0x02: fprintf(stdout, _("call in progress\n"));          break; /* ringing or already answered call */
2269       case 0x03: fprintf(stdout, _("waiting for security code\n")); break;
2270       case 0x04: fprintf(stdout, _("powered off\n"));               break;
2271       default  : fprintf(stdout, _("unknown\n"));
2272
2273     }
2274
2275     fprintf(stdout, _("   Power source: "));
2276
2277     switch (MessageBuffer[7]) {
2278
2279       case 0x01: fprintf(stdout, _("AC/DC\n"));   break;
2280       case 0x02: fprintf(stdout, _("battery\n")); break;
2281       default  : fprintf(stdout, _("unknown\n"));
2282
2283     }
2284
2285     fprintf(stdout, _("   Battery Level: %d\n"), MessageBuffer[8]);
2286     fprintf(stdout, _("   Signal strength: %d\n"), MessageBuffer[5]);
2287 #endif /* DEBUG */
2288
2289     CurrentRFLevel=MessageBuffer[5];
2290     CurrentBatteryLevel=MessageBuffer[8];
2291     CurrentPowerSource=MessageBuffer[7];
2292 }
2293
2294
2295 GSM_Error N6110_GetRFLevel(GSM_RFUnits *units, float *level)
2296 {
2297
2298   /* FIXME - these values are from 3810 code, may be incorrect.  Map from
2299      values returned in status packet to the the values returned by the AT+CSQ
2300      command. */
2301   float csq_map[5] = {0, 8, 16, 24, 31};
2302
2303   int timeout=10;
2304   int rf_level;
2305   
2306   char screen[NM_MAX_SCREEN_WIDTH];
2307
2308   CurrentRFLevel=-1;
2309     
2310   if (GetModelFeature (FN_NOPOWERFRAME)==F_NOPOWER) {
2311
2312 #ifndef UCLINUX
2313     if (N6110_NetMonitor(1, screen)!=GE_NONE)
2314       return GE_INTERNALERROR;
2315 #endif /* UCLINUX */
2316     
2317     rf_level=4;
2318     
2319     if (screen[4]!='-') {
2320       if (screen[5]=='9' && screen[6]>'4') rf_level=1;
2321       if (screen[5]=='9' && screen[6]<'5') rf_level=2;
2322       if (screen[5]=='8' && screen[6]>'4') rf_level=3;      
2323     } else rf_level=0;
2324
2325     /* Arbitrary units. */
2326     if (*units == GRF_Arbitrary) {
2327       *level = rf_level;
2328       return (GE_NONE);
2329     }
2330     
2331   } else {
2332     N6110_SendStatusRequest();
2333
2334     /* Wait for timeout or other error. */
2335     while (timeout != 0 && CurrentRFLevel == -1 ) {
2336
2337       if (--timeout == 0)
2338         return (GE_TIMEOUT);
2339
2340       usleep (100000);
2341     }
2342
2343     /* Make copy in case it changes. */
2344     rf_level = CurrentRFLevel;
2345
2346     if (rf_level == -1)
2347       return (GE_NOLINK);
2348
2349     /* Now convert between the different units we support. */
2350
2351     /* Arbitrary units. */
2352     if (*units == GRF_Arbitrary) {
2353       *level = rf_level;
2354       return (GE_NONE);
2355     }
2356
2357     /* CSQ units. */
2358     if (*units == GRF_CSQ) {
2359
2360       if (rf_level <=4)
2361         *level = csq_map[rf_level];
2362       else
2363         *level = 99; /* Unknown/undefined */
2364
2365       return (GE_NONE);
2366     }
2367   }
2368
2369   /* Unit type is one we don't handle so return error */
2370   return (GE_INTERNALERROR);
2371 }
2372
2373
2374 GSM_Error N6110_GetBatteryLevel(GSM_BatteryUnits *units, float *level)
2375 {
2376   int timeout=10;
2377   int batt_level;
2378
2379   char screen[NM_MAX_SCREEN_WIDTH];
2380
2381   CurrentBatteryLevel=-1;
2382
2383   if (GetModelFeature (FN_NOPOWERFRAME)==F_NOPOWER) {
2384
2385 #ifndef UCLINUX
2386     if (N6110_NetMonitor(23, screen)!=GE_NONE)
2387       return GE_NOLINK;
2388 #endif /* UCLINUX */
2389     
2390     batt_level=4;
2391     
2392     if (screen[29]=='7') batt_level=3;
2393     if (screen[29]=='5') batt_level=2;
2394     if (screen[29]=='2') batt_level=1;
2395     
2396     /* Only units we handle at present are GBU_Arbitrary */
2397     if (*units == GBU_Arbitrary) {
2398       *level = batt_level;
2399       return (GE_NONE);
2400     }
2401
2402     return (GE_INTERNALERROR);    
2403     
2404   } else {
2405     N6110_SendStatusRequest();
2406
2407     /* Wait for timeout or other error. */
2408     while (timeout != 0 && CurrentBatteryLevel == -1 ) {
2409
2410       if (--timeout == 0)
2411         return (GE_TIMEOUT);
2412
2413       usleep (100000);
2414     }
2415
2416     /* Take copy in case it changes. */
2417     batt_level = CurrentBatteryLevel;
2418
2419     if (batt_level != -1) {
2420
2421       /* Only units we handle at present are GBU_Arbitrary */
2422       if (*units == GBU_Arbitrary) {
2423         *level = batt_level;
2424         return (GE_NONE);
2425       }
2426
2427       return (GE_INTERNALERROR);
2428     }
2429     else
2430       return (GE_NOLINK);
2431   }
2432 }
2433
2434 GSM_Error N6110_GetPowerSource(GSM_PowerSource *source)
2435 {
2436
2437   int timeout=10;
2438
2439   char screen[NM_MAX_SCREEN_WIDTH];
2440
2441   CurrentPowerSource=-1;
2442
2443   if (GetModelFeature (FN_NOPOWERFRAME)==F_NOPOWER) {    
2444
2445 #ifndef UCLINUX
2446     if (N6110_NetMonitor(20, screen)!=GE_NONE)
2447       return GE_NOLINK;
2448 #endif /* UCLINUX */
2449     
2450     CurrentPowerSource=GPS_ACDC;
2451
2452     if (screen[6]=='x') CurrentPowerSource=GPS_BATTERY;
2453
2454     *source=CurrentPowerSource;        
2455     
2456     return GE_NONE;    
2457   } else {
2458     N6110_SendStatusRequest();
2459
2460     /* Wait for timeout or other error. */
2461     while (timeout != 0 && CurrentPowerSource == -1 ) {
2462
2463       if (--timeout == 0)
2464         return (GE_TIMEOUT);
2465
2466       usleep (100000);
2467     }
2468
2469     if (CurrentPowerSource != -1) {
2470       *source=CurrentPowerSource;
2471       return (GE_NONE);
2472     }
2473     else
2474       return (GE_NOLINK);
2475   }
2476 }
2477
2478 #ifndef UCLINUX
2479
2480 static void N6110_ReplyGetDisplayStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2481
2482   int i;
2483
2484   for (i=0; i<MessageBuffer[4];i++)
2485     if (MessageBuffer[2*i+6]==2)
2486       CurrentDisplayStatus|=1<<(MessageBuffer[2*i+5]-1);
2487     else
2488       CurrentDisplayStatus&= (0xff - (1<<(MessageBuffer[2*i+5]-1)));
2489
2490 #ifdef DEBUG
2491   fprintf(stdout, _("Call in progress: %s\n"), CurrentDisplayStatus & (1<<DS_Call_In_Progress)?"on":"off");
2492   fprintf(stdout, _("Unknown: %s\n"),          CurrentDisplayStatus & (1<<DS_Unknown)?"on":"off");
2493   fprintf(stdout, _("Unread SMS: %s\n"),       CurrentDisplayStatus & (1<<DS_Unread_SMS)?"on":"off");
2494   fprintf(stdout, _("Voice call: %s\n"),       CurrentDisplayStatus & (1<<DS_Voice_Call)?"on":"off");
2495   fprintf(stdout, _("Fax call active: %s\n"),  CurrentDisplayStatus & (1<<DS_Fax_Call)?"on":"off");
2496   fprintf(stdout, _("Data call active: %s\n"), CurrentDisplayStatus & (1<<DS_Data_Call)?"on":"off");
2497   fprintf(stdout, _("Keyboard lock: %s\n"),    CurrentDisplayStatus & (1<<DS_Keyboard_Lock)?"on":"off");
2498   fprintf(stdout, _("SMS storage full: %s\n"), CurrentDisplayStatus & (1<<DS_SMS_Storage_Full)?"on":"off");
2499 #endif /* DEBUG */
2500
2501   CurrentDisplayStatusError=GE_NONE;
2502 }
2503
2504 GSM_Error N6110_GetDisplayStatus(int *Status) {
2505
2506   unsigned char req[4]={ N6110_FRAME_HEADER, 0x51 };
2507
2508   GSM_Error error;
2509
2510   error=NULL_SendMessageSequence
2511     (10, &CurrentDisplayStatusError, 4, 0x0d, req);
2512   if (error!=GE_NONE) return error;
2513   
2514   *Status=CurrentDisplayStatus;
2515
2516   return GE_NONE;
2517 }
2518
2519 GSM_Error N6110_DialVoice(char *Number) {
2520 /* This commented sequence doesn't work on N3210/3310/6210/7110 */
2521 //  unsigned char req[64]={N6110_FRAME_HEADER, 0x01};
2522 //  unsigned char req_end[]={0x05, 0x01, 0x01, 0x05, 0x81, 0x01, 0x00, 0x00, 0x01};
2523 //  int i=0;
2524 //  req[4]=strlen(Number);
2525 //  for(i=0; i < strlen(Number) ; i++)
2526 //   req[5+i]=Number[i];
2527 //  memcpy(req+5+strlen(Number), req_end, 10);
2528 //  return NULL_SendMessageSequence
2529 //    (20, &CurrentDialVoiceError, 13+strlen(Number), 0x01, req);
2530
2531   unsigned char req[64]={0x00,0x01,0x7c,
2532                          0x01}; //call command
2533
2534   int i=0;                       
2535   
2536   GSM_Error error;
2537
2538   error=N6110_EnableExtendedCommands(0x01);
2539   if (error!=GE_NONE) return error;
2540
2541   for(i=0; i < strlen(Number) ; i++) req[4+i]=Number[i];
2542   
2543   req[4+i+1]=0;
2544   
2545   return NULL_SendMessageSequence
2546     (20, &CurrentDialVoiceError, 4+strlen(Number)+1, 0x40, req);  
2547 }
2548
2549 #endif /* UCLINUX */
2550
2551 /* Dial a data call - type specifies request to use: 
2552      type 0 should normally be used
2553      type 1 should be used when calling a digital line - corresponds to ats35=0
2554      Maybe one day we'll know what they mean!
2555 */
2556 GSM_Error N6110_DialData(char *Number, char type, void (* callpassup)(char c))
2557 {
2558         unsigned char req[100]   = { N6110_FRAME_HEADER, 0x01 };
2559         unsigned char *req_end;
2560         unsigned char req_end0[] = { 0x01,  /* make a data call = type 0x01 */
2561                                      0x02,0x01,0x05,0x81,0x01,0x00,0x00,0x01,0x02,0x0a,
2562                                      0x07,0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00 };
2563         unsigned char req_end1[] = { 0x01,
2564                                      0x02,0x01,0x05,0x81,0x01,0x00,0x00,0x01,0x02,0x0a,
2565                                      0x07,0xa1,0x88,0x89,0x21,0x15,0x63,0xa0,0x00,0x06,
2566                                      0x88,0x90,0x21,0x48,0x40,0xbb };
2567         unsigned char req2[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x01,
2568                                      0x07,0xa2,0xc8,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
2569                                      0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80,0x01,0x60 };
2570         unsigned char req3[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x01,
2571                                      0x07,0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
2572                                      0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80 };
2573         unsigned char req4[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x81,
2574                                      0x07,0xa1,0x88,0x89,0x21,0x15,0x63,0xa0,0x00,0x06,
2575                                      0x88,0x90,0x21,0x48,0x40,0xbb,0x07,0xa3,0xb8,0x81,
2576                                      0x20,0x15,0x63,0x80 };
2577
2578         int i = 0;
2579         u8 size;
2580
2581         CurrentCallPassup=callpassup;
2582
2583         switch (type) {
2584         case 0:
2585                 req_end = req_end0;
2586                 size = sizeof(req_end0);
2587                 break;
2588         case 1:
2589                 Protocol->SendMessage(sizeof(req3), 0x01, req3);
2590                 Protocol->SendMessage(sizeof(req4), 0x01, req4);
2591                 req_end = req_end1;
2592                 size = sizeof(req_end1);
2593                 break;
2594         case -1:   /* Just used to set the call passup */
2595                 return GE_NONE;
2596                 break;
2597         default:
2598                 req_end = req_end0;
2599                 size = sizeof(req_end0);
2600                 break;
2601         }
2602
2603         req[4] = strlen(Number);
2604
2605         for(i = 0; i < strlen(Number) ; i++)
2606                 req[5+i] = Number[i];
2607
2608         memcpy(req + 5 + strlen(Number), req_end, size);
2609
2610         Protocol->SendMessage(5 + size + strlen(Number), 0x01, req);
2611         if (type != 1) Protocol->SendMessage(26, 0x01, req2);
2612
2613         return (GE_NONE);
2614 }
2615
2616 #ifndef UCLINUX
2617
2618 GSM_Error N6110_GetIncomingCallNr(char *Number)
2619 {
2620
2621   if (*CurrentIncomingCall != ' ') {
2622     strcpy(Number, CurrentIncomingCall);
2623     return GE_NONE;
2624   }
2625   else
2626     return GE_BUSY;
2627 }
2628
2629 #endif /* UCLINUX */
2630
2631 GSM_Error N6110_CancelCall(void)
2632 {
2633 //  This frame & method works only on 61xx/51xx
2634 //  unsigned char req[] = { N6110_FRAME_HEADER, 0x08, 0x00, 0x85};
2635 //  req[4]=CurrentCallSequenceNumber;
2636 //  Protocol->SendMessage(6, 0x01, req);
2637 //  return GE_NONE;
2638  
2639   GSM_Error error;
2640
2641   unsigned char req[]={0x00,0x01,0x7c,0x03};
2642     
2643   /* Checking */
2644   error=N6110_EnableExtendedCommands(0x01);
2645   if (error!=GE_NONE) return error;
2646
2647   return NULL_SendMessageSequence (20, &CurrentDialVoiceError, 4, 0x40, req);   
2648 }  
2649
2650 #ifndef UCLINUX
2651
2652 void N6110_ReplyEnterSecurityCode(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2653     
2654   switch(MessageBuffer[3]) {
2655
2656   case 0x0b:
2657 #ifdef DEBUG
2658     fprintf(stdout, _("Message: Security code accepted.\n"));
2659 #endif /* DEBUG */
2660     CurrentSecurityCodeError = GE_NONE;
2661     break;
2662
2663   default:
2664 #ifdef DEBUG
2665     fprintf(stdout, _("Message: Security code is wrong. You're not my big owner :-)\n"));
2666 #endif /* DEBUG */
2667     CurrentSecurityCodeError = GE_INVALIDSECURITYCODE;
2668   }
2669 }
2670
2671 GSM_Error N6110_EnterSecurityCode(GSM_SecurityCode SecurityCode)
2672 {
2673
2674   unsigned char req[15] = { N6110_FRAME_HEADER,
2675                             0x0a, /* Enter code request. */
2676                             0x00  /* Type of the entered code. */
2677                             };
2678   int i=0;
2679
2680   req[4]=SecurityCode.Type;
2681
2682   for (i=0; i<strlen(SecurityCode.Code);i++)
2683     req[5+i]=SecurityCode.Code[i];
2684
2685   req[5+strlen(SecurityCode.Code)]=0x00;
2686   req[6+strlen(SecurityCode.Code)]=0x00;
2687
2688   return NULL_SendMessageSequence
2689     (20, &CurrentSecurityCodeError, 7+strlen(SecurityCode.Code), 0x08, req);
2690 }
2691
2692 void N6110_ReplyGetSecurityCodeStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2693     
2694   *CurrentSecurityCodeStatus = MessageBuffer[4];
2695
2696 #ifdef DEBUG
2697   fprintf(stdout, _("Message: Security Code status received: "));
2698
2699   switch(*CurrentSecurityCodeStatus) {
2700
2701     case GSCT_SecurityCode: fprintf(stdout, _("waiting for Security Code.\n")); break;
2702     case GSCT_Pin         : fprintf(stdout, _("waiting for PIN.\n")); break;
2703     case GSCT_Pin2        : fprintf(stdout, _("waiting for PIN2.\n")); break;
2704     case GSCT_Puk         : fprintf(stdout, _("waiting for PUK.\n")); break;
2705     case GSCT_Puk2        : fprintf(stdout, _("waiting for PUK2.\n")); break;
2706     case GSCT_None        : fprintf(stdout, _("nothing to enter.\n")); break;
2707     default               : fprintf(stdout, _("Unknown!\n"));
2708   }
2709       
2710 #endif /* DEBUG */
2711
2712   CurrentSecurityCodeError = GE_NONE;
2713 }
2714
2715 GSM_Error N6110_GetSecurityCodeStatus(int *Status)
2716 {
2717
2718   unsigned char req[4] = { N6110_FRAME_HEADER,
2719                            0x07
2720                          };
2721
2722   CurrentSecurityCodeStatus=Status;
2723
2724   return NULL_SendMessageSequence
2725     (20, &CurrentSecurityCodeError, 4, 0x08, req);
2726 }
2727
2728 void N6110_ReplyGetSecurityCode(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2729
2730   int i;
2731   
2732 #ifdef DEBUG
2733   fprintf(stdout, _("Message: Security code received: "));
2734   switch (MessageBuffer[3]) {
2735     case GSCT_SecurityCode: fprintf(stdout, _("Security code"));break;
2736     case GSCT_Pin:  fprintf(stdout, _("PIN"));break;
2737     case GSCT_Pin2: fprintf(stdout, _("PIN2"));break;
2738     case GSCT_Puk:  fprintf(stdout, _("PUK"));break;
2739     case GSCT_Puk2: fprintf(stdout, _("PUK2"));break;
2740     default: fprintf(stdout, _("unknown !"));break;
2741   }
2742   if (MessageBuffer[4]==1) {
2743     fprintf(stdout, _(" allowed, value \""));
2744     if (MessageBuffer[3]==GSCT_SecurityCode) {
2745       for (i=0;i<5;i++) {fprintf(stdout, _("%c"), MessageBuffer[5+i]);}
2746     }
2747     if (MessageBuffer[3]==GSCT_Pin || MessageBuffer[3]==GSCT_Pin2 ||
2748         MessageBuffer[3]==GSCT_Puk || MessageBuffer[3]==GSCT_Puk2) {
2749       for (i=0;i<4;i++) {fprintf(stdout, _("%c"), MessageBuffer[5+i]);}
2750     }
2751     fprintf(stdout, _("\""));
2752   } else {
2753     fprintf(stdout, _(" not allowed"));  
2754   }
2755   fprintf(stdout, _("\n"));  
2756 #endif /* DEBUG */
2757       
2758   if (CurrentSecurityCode->Type==MessageBuffer[3] /* We wanted this code */
2759           && MessageBuffer[4]==1) {                      /* It's allowed */
2760     if (MessageBuffer[3]==GSCT_SecurityCode) {
2761       for (i=0;i<5;i++) {CurrentSecurityCode->Code[i]=MessageBuffer[5+i];}
2762       CurrentSecurityCode->Code[5]=0;
2763     }
2764     if (MessageBuffer[3]==GSCT_Pin || MessageBuffer[3]==GSCT_Pin2 ||
2765         MessageBuffer[3]==GSCT_Puk || MessageBuffer[3]==GSCT_Puk2) {
2766       for (i=0;i<4;i++) {CurrentSecurityCode->Code[i]=MessageBuffer[5+i];}
2767       CurrentSecurityCode->Code[4]=0;
2768     }
2769     CurrentSecurityCodeError=GE_NONE;
2770   } else
2771     CurrentSecurityCodeError=GE_INVALIDSECURITYCODE;
2772 }
2773
2774 GSM_Error N6110_GetSecurityCode(GSM_SecurityCode *SecurityCode)
2775 {
2776
2777   unsigned char req[4] = { 0x00,
2778                            0x01,0x6e, /* Get code request. */
2779                            0x00 };    /* Type of the requested code. */
2780
2781   GSM_Error error;
2782   
2783   error=N6110_EnableExtendedCommands(0x01);
2784   if (error!=GE_NONE) return error;
2785   
2786   req[3]=SecurityCode->Type;
2787
2788   CurrentSecurityCode=SecurityCode;
2789
2790   return NULL_SendMessageSequence
2791     (20, &CurrentSecurityCodeError, 4, 0x40, req);
2792 }
2793
2794 void N6110_ReplyPlayTone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2795
2796 #ifdef DEBUG
2797   fprintf(stdout, _("Message: answer for PlayTone frame\n"));      
2798 #endif
2799       
2800   CurrentPlayToneError=GE_NONE;      
2801 }
2802
2803 GSM_Error N6110_PlayTone(int Herz, u8 Volume)
2804 {
2805   unsigned char req[6] = { 0x00,0x01,0x8f,
2806                            0x00,   /* Volume */
2807                            0x00,   /* HerzLo */
2808                            0x00 }; /* HerzHi */
2809
2810   GSM_Error error;
2811
2812   /* PlayTone wasn't used earlier */
2813   if (CurrentPlayToneError==GE_UNKNOWN) {
2814     if (CurrentConnectionType!=GCT_MBUS)
2815       CurrentDisableKeepAlive=true;
2816
2817     error=N6110_EnableExtendedCommands(0x01);
2818     if (error!=GE_NONE) return error;
2819   }
2820
2821   /* For Herz==255*255 we have silent */  
2822   if (Herz!=255*255) {
2823     req[3]=Volume;
2824
2825     req[5]=Herz%256;
2826     req[4]=Herz/256;
2827   } else {
2828     req[3]=0;
2829
2830     req[5]=0;
2831     req[4]=0;
2832   }
2833
2834 #ifdef WIN32
2835   /* For Herz==255*255 we have silent and additionaly
2836      we wait for phone answer - it's important for MBUS */
2837   if (Herz==255*255) {
2838     error=NULL_SendMessageSequence
2839       (20, &CurrentPlayToneError, 6, 0x40, req);
2840
2841     CurrentPlayToneError=GE_UNKNOWN;
2842     CurrentDisableKeepAlive=false;
2843
2844     if (error!=GE_NONE) return error;
2845   } else {
2846     Protocol->SendMessage(6,0x40,req);
2847   }
2848 #else
2849   error=NULL_SendMessageSequence
2850     (20, &CurrentPlayToneError, 6, 0x40, req);
2851
2852   /* For Herz==255*255 we wait for phone answer - it's important for MBUS */
2853   if (Herz==255*255) {
2854     CurrentPlayToneError=GE_UNKNOWN;
2855     CurrentDisableKeepAlive=false;
2856   }
2857   
2858   if (error!=GE_NONE) return error;
2859
2860 #endif
2861     
2862   return(GE_NONE);
2863 }
2864
2865 void N6110_ReplyGetDateTime(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2866
2867   if (MessageBuffer[4]==0x01) {
2868     DecodeDateTime(MessageBuffer+8, CurrentDateTime);
2869
2870 #ifdef DEBUG
2871     fprintf(stdout, _("Message: Date and time\n"));
2872     fprintf(stdout, _("   Time: %02d:%02d:%02d\n"), CurrentDateTime->Hour, CurrentDateTime->Minute, CurrentDateTime->Second);
2873     fprintf(stdout, _("   Date: %4d/%02d/%02d\n"), CurrentDateTime->Year, CurrentDateTime->Month, CurrentDateTime->Day);
2874 #endif /* DEBUG */
2875
2876     CurrentDateTime->IsSet=true;
2877   } else {
2878
2879 #ifdef DEBUG
2880     fprintf(stdout, _("Message: Date and time not set in phone\n"));
2881 #endif
2882
2883     CurrentDateTime->IsSet=false;
2884   }
2885       
2886   CurrentDateTimeError=GE_NONE;
2887 }
2888
2889 GSM_Error N6110_GetDateTime(GSM_DateTime *date_time)
2890 {
2891   return N6110_PrivGetDateTime(date_time,0x11);
2892 }
2893
2894 GSM_Error N6110_PrivGetDateTime(GSM_DateTime *date_time, int msgtype)
2895 {
2896   unsigned char req[] = {N6110_FRAME_HEADER, 0x62};
2897
2898   CurrentDateTime=date_time;
2899
2900   return NULL_SendMessageSequence
2901     (50, &CurrentDateTimeError, 4, msgtype, req);
2902 }
2903
2904 void N6110_ReplyGetAlarm(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2905
2906 #ifdef DEBUG
2907   fprintf(stdout, _("Message: Alarm\n"));
2908   fprintf(stdout, _("   Alarm: %02d:%02d\n"), MessageBuffer[9], MessageBuffer[10]);
2909   fprintf(stdout, _("   Alarm is %s\n"), (MessageBuffer[8]==2) ? _("on"):_("off"));
2910 #endif /* DEBUG */
2911
2912   CurrentAlarm->Hour=MessageBuffer[9];
2913   CurrentAlarm->Minute=MessageBuffer[10];
2914   CurrentAlarm->Second=0;
2915
2916   CurrentAlarm->IsSet=(MessageBuffer[8]==2);
2917
2918   CurrentAlarmError=GE_NONE;
2919 }
2920
2921 GSM_Error N6110_GetAlarm(int alarm_number, GSM_DateTime *date_time)
2922 {
2923   return N6110_PrivGetAlarm(alarm_number,date_time,0x11);
2924 }
2925
2926 GSM_Error N6110_PrivGetAlarm(int alarm_number, GSM_DateTime *date_time, int msgtype)
2927 {
2928   unsigned char req[] = {N6110_FRAME_HEADER, 0x6d};
2929
2930   CurrentAlarm=date_time;
2931
2932   return NULL_SendMessageSequence
2933     (50, &CurrentAlarmError, 4, msgtype, req);
2934 }
2935
2936 void N6110_ReplyGetSMSCenter(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2937   
2938   switch (MessageBuffer[3]) {
2939
2940   case 0x34:
2941
2942     CurrentMessageCenter->No=MessageBuffer[4];
2943     CurrentMessageCenter->Format=MessageBuffer[6];
2944     CurrentMessageCenter->Validity=MessageBuffer[8];
2945     sprintf(CurrentMessageCenter->Name, "%s", MessageBuffer+33);
2946
2947     sprintf(CurrentMessageCenter->DefaultRecipient, "%s", GSM_UnpackSemiOctetNumber(MessageBuffer+9,false));
2948
2949     sprintf(CurrentMessageCenter->Number, "%s", GSM_UnpackSemiOctetNumber(MessageBuffer+21,false));
2950       
2951 #ifdef DEBUG
2952     fprintf(stdout, _("Message: SMS Center received:\n"));
2953     fprintf(stdout, _("   %d. SMS Center name is %s\n"), CurrentMessageCenter->No, CurrentMessageCenter->Name);
2954     fprintf(stdout, _("   SMS Center number is %s\n"), CurrentMessageCenter->Number);
2955     fprintf(stdout, _("   Default recipient number is %s\n"), CurrentMessageCenter->DefaultRecipient);
2956       
2957     fprintf(stdout, _("   SMS Center message format is "));
2958
2959     switch (CurrentMessageCenter->Format) {
2960
2961       case GSMF_Text  : fprintf(stdout, _("Text"));   break;
2962       case GSMF_Paging: fprintf(stdout, _("Paging")); break;
2963       case GSMF_Fax   : fprintf(stdout, _("Fax"));    break;
2964       case GSMF_Email : fprintf(stdout, _("Email"));  break;
2965       default         : fprintf(stdout, _("Unknown"));
2966     }
2967
2968     fprintf(stdout, "\n");
2969
2970     fprintf(stdout, _("   SMS Center message validity is "));
2971
2972     switch (CurrentMessageCenter->Validity) {
2973
2974       case GSMV_1_Hour  : fprintf(stdout, _("1 hour"));      break;
2975       case GSMV_6_Hours : fprintf(stdout, _("6 hours"));     break;
2976       case GSMV_24_Hours: fprintf(stdout, _("24 hours"));    break;
2977       case GSMV_72_Hours: fprintf(stdout, _("72 hours"));    break;
2978       case GSMV_1_Week  : fprintf(stdout, _("1 week"));      break;
2979       case GSMV_Max_Time: fprintf(stdout, _("Maximum time"));break;
2980       default           : fprintf(stdout, _("Unknown"));
2981     }
2982
2983     fprintf(stdout, "\n");
2984
2985 #endif /* DEBUG */
2986
2987     CurrentMessageCenterError=GE_NONE;
2988
2989     break;
2990
2991   case 0x35:
2992
2993     /* Number of entries depends on SIM card */
2994
2995 #ifdef DEBUG
2996     fprintf(stdout, _("Message: SMS Center error received:\n"));
2997     fprintf(stdout, _("   The request for SMS Center failed.\n"));
2998 #endif /* DEBUG */
2999
3000     /* FIXME: appropriate error. */
3001     CurrentMessageCenterError=GE_INTERNALERROR;
3002
3003     break;  
3004
3005   }
3006 }
3007
3008 /* This function sends to the mobile phone a request for the SMS Center */
3009 GSM_Error N6110_GetSMSCenter(GSM_MessageCenter *MessageCenter)
3010 {
3011   unsigned char req[] = { N6110_FRAME_HEADER, 0x33, 0x64,
3012                           0x00 /* SMS Center Number. */
3013                         };
3014
3015   req[5]=MessageCenter->No;
3016
3017   CurrentMessageCenter=MessageCenter;
3018
3019   return NULL_SendMessageSequence
3020     (50, &CurrentMessageCenterError, 6, 0x02, req);
3021 }
3022
3023 void N6110_ReplySetSMSCenter(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3024
3025 #ifdef DEBUG
3026   fprintf(stdout, _("Message: SMS Center correctly set.\n"));
3027 #endif
3028   CurrentMessageCenterError=GE_NONE;
3029 }
3030
3031 /* This function set the SMS Center profile on the phone. */
3032 GSM_Error N6110_SetSMSCenter(GSM_MessageCenter *MessageCenter)
3033 {
3034   unsigned char req[64] = { N6110_FRAME_HEADER, 0x30, 0x64,
3035                             0x00, /* SMS Center Number. */
3036                             0x00, /* Unknown. */
3037                             0x00, /* SMS Message Format. */
3038                             0x00, /* Unknown. */
3039                             0x00, /* Validity. */
3040                             0,0,0,0,0,0,0,0,0,0,0,0, /* Default recipient number */
3041                             0,0,0,0,0,0,0,0,0,0,0,0 /* Message Center Number. */
3042                             /* Message Center Name. */
3043                           };
3044
3045   req[5]=MessageCenter->No;
3046   req[7]=MessageCenter->Format;
3047   req[9]=MessageCenter->Validity;
3048
3049   req[10]=GSM_PackSemiOctetNumber(MessageCenter->DefaultRecipient, req+11, false);
3050
3051   req[22]=GSM_PackSemiOctetNumber(MessageCenter->Number, req+23, false);
3052
3053   sprintf(req+34, "%s", MessageCenter->Name);
3054
3055   CurrentMessageCenter=MessageCenter;
3056
3057   return NULL_SendMessageSequence
3058     (50, &CurrentMessageCenterError, 35+strlen(MessageCenter->Name), 0x02, req);
3059 }
3060
3061 void N6110_ReplyGetSMSStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3062
3063   switch (MessageBuffer[3]) {
3064
3065   case 0x37:
3066
3067 #ifdef DEBUG
3068     fprintf(stdout, _("Message: SMS Status Received\n"));
3069     fprintf(stdout, _("   The number of messages: %d\n"), MessageBuffer[10]);
3070     fprintf(stdout, _("   Unread messages: %d\n"), MessageBuffer[11]);
3071 #endif /* DEBUG */
3072
3073     CurrentSMSStatus->UnRead = MessageBuffer[11];
3074     CurrentSMSStatus->Number = MessageBuffer[10];
3075     
3076     CurrentSMSStatusError = GE_NONE;
3077     break;
3078
3079   case 0x38:
3080
3081 #ifdef DEBUG
3082     fprintf(stdout, _("Message: SMS Status error, probably not authorized by PIN\n"));
3083 #endif /* DEBUG */
3084
3085     CurrentSMSStatusError = GE_INTERNALERROR;
3086     break;
3087           
3088   }
3089 }
3090
3091 GSM_Error N6110_GetSMSStatus(GSM_SMSStatus *Status)
3092 {
3093   unsigned char req[] = {N6110_FRAME_HEADER, 0x36, 0x64};
3094
3095   CurrentSMSStatus = Status;
3096
3097   return NULL_SendMessageSequence
3098     (10, &CurrentSMSStatusError, 5, 0x14, req);
3099 }
3100
3101 GSM_Error N6110_GetSMSFolders ( GSM_SMSFolders *folders)
3102 {
3103   folders->number=2;
3104
3105   strcpy(folders->Folder[0].Name,"Inbox");
3106   strcpy(folders->Folder[1].Name,"Outbox");
3107   
3108   return GE_NONE;
3109 }
3110
3111 GSM_Error N6110_GetIMEI(char *imei)
3112 {
3113   if (strlen(Current_IMEI)>0) {
3114     strncpy (imei, Current_IMEI, GSM_MAX_IMEI_LENGTH);
3115     return (GE_NONE);
3116   }
3117   else
3118     return (GE_TRYAGAIN);
3119 }
3120
3121 GSM_Error N6110_GetRevision(char *revision)
3122 {
3123
3124   if (strlen(Current_Revision)>0) {
3125     strncpy (revision, Current_Revision, GSM_MAX_REVISION_LENGTH);
3126     return (GE_NONE);
3127   }
3128   else
3129     return (GE_TRYAGAIN);
3130 }
3131
3132 #endif /* UCLINUX */
3133
3134 static GSM_Error N6110_GetModel(char *model)
3135 {
3136   if (strlen(Current_Model)>0) {
3137     strncpy (model, Current_Model, GSM_MAX_MODEL_LENGTH);
3138     return (GE_NONE);
3139   }
3140   else
3141     return (GE_TRYAGAIN);
3142 }
3143
3144 #ifndef UCLINUX
3145
3146 void N6110_ReplySetDateTime(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3147
3148   switch (MessageBuffer[4]) {
3149
3150     case 0x01:
3151 #ifdef DEBUG
3152       fprintf(stdout, _("Message: Date and time set correctly\n"));
3153 #endif /* DEBUG */
3154       CurrentSetDateTimeError=GE_NONE;
3155       break;
3156       
3157     default:
3158 #ifdef DEBUG
3159       fprintf(stdout, _("Message: Date and time setting error\n"));
3160 #endif /* DEBUG */
3161       CurrentSetDateTimeError=GE_INVALIDDATETIME;
3162
3163   }
3164 }
3165
3166 /* Needs SIM card with PIN in phone */
3167 GSM_Error N6110_SetDateTime(GSM_DateTime *date_time)
3168 {
3169   return N6110_PrivSetDateTime(date_time,0x11);
3170 }
3171
3172 /* Needs SIM card with PIN in phone */
3173 GSM_Error N6110_PrivSetDateTime(GSM_DateTime *date_time, int msgtype)
3174 {
3175
3176   unsigned char req[] = { N6110_FRAME_HEADER,
3177                           0x60, /* set-time subtype */
3178                           0x01, 0x01, 0x07, /* unknown */
3179                           0x00, 0x00, /* Year (0x07cf = 1999) */
3180                           0x00, 0x00, /* Month Day */
3181                           0x00, 0x00, /* Hours Minutes */
3182                           0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
3183                         };
3184
3185   EncodeDateTime(req+7, date_time);
3186
3187   return NULL_SendMessageSequence
3188     (20, &CurrentSetDateTimeError, 14, msgtype, req);
3189 }
3190
3191 void N6110_ReplySetAlarm(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3192
3193   switch (MessageBuffer[4]) {
3194
3195     case 0x01:
3196 #ifdef DEBUG
3197       fprintf(stdout, _("Message: Alarm set correctly\n"));
3198 #endif /* DEBUG */
3199       CurrentSetAlarmError=GE_NONE;
3200       break;
3201       
3202     default:
3203 #ifdef DEBUG
3204       fprintf(stdout, _("Message: Alarm setting error\n"));
3205 #endif /* DEBUG */
3206       CurrentSetAlarmError=GE_INVALIDDATETIME;
3207
3208   }
3209 }
3210
3211 /* FIXME: we should also allow to set the alarm off :-) */
3212 GSM_Error N6110_SetAlarm(int alarm_number, GSM_DateTime *date_time)
3213 {
3214   return N6110_PrivSetAlarm(alarm_number,date_time, 0x11);
3215 }
3216
3217 /* FIXME: we should also allow to set the alarm off :-) */
3218 GSM_Error N6110_PrivSetAlarm(int alarm_number, GSM_DateTime *date_time, int msgtype)
3219 {
3220
3221   unsigned char req[] = { N6110_FRAME_HEADER,
3222                           0x6b, /* set-alarm subtype */
3223                           0x01, 0x20, 0x03, /* unknown */
3224                           0x02,       /* should be alarm on/off, but it don't works */
3225                           0x00, 0x00, /* Hours Minutes */
3226                           0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
3227                         };
3228
3229   req[8] = date_time->Hour;
3230   req[9] = date_time->Minute;
3231
3232   return NULL_SendMessageSequence
3233     (50, &CurrentSetAlarmError, 11, msgtype, req);
3234 }
3235
3236 #endif /* UCLINUX */
3237
3238 static void N6110_ReplyGetMemoryLocation(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3239
3240   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
3241   char model[64];
3242
3243   int i, tmp, count;
3244     
3245   switch (MessageBuffer[3]) {
3246
3247   case 0x02:
3248
3249     CurrentPhonebookEntry->Empty = true;
3250
3251     count=MessageBuffer[5];
3252           
3253 #ifdef DEBUG
3254     fprintf(stdout, _("Message: Phonebook entry received:\n"));
3255     fprintf(stdout, _("   Name: "));
3256
3257     for (tmp=0; tmp <count; tmp++)
3258     {
3259       if (MessageBuffer[6+tmp]==1) fprintf(stdout, "%c", '~'); else //enables/disables blinking
3260       if (MessageBuffer[6+tmp]==0) fprintf(stdout, "%c", '`'); else //hides rest ot contents
3261       fprintf(stdout, "%c", MessageBuffer[6+tmp]);
3262     }
3263
3264     fprintf(stdout, "\n");
3265 #endif /* DEBUG */
3266
3267     while (N6110_GetModel(model)  != GE_NONE)
3268       sleep(1);
3269         
3270     if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {//pbk with Unicode
3271       DecodeUnicode (CurrentPhonebookEntry->Name, MessageBuffer+6, count/2);
3272       CurrentPhonebookEntry->Name[count/2] = 0x00;
3273     } else {
3274       memcpy(CurrentPhonebookEntry->Name, MessageBuffer + 6, count);
3275       CurrentPhonebookEntry->Name[count] = 0x00;
3276     }
3277
3278     CurrentPhonebookEntry->Empty = false;
3279
3280     for (tmp=0; tmp <count; tmp++)
3281     {
3282       if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {//pbk with Unicode
3283         /* We check only 1'st, 3'rd, ... char */
3284         if (tmp%2!=0 && MessageBuffer[6+tmp]==1) CurrentPhonebookEntry->Name[tmp/2]='~'; //enables/disables blinking
3285         if (tmp%2!=0 && MessageBuffer[6+tmp]==0) CurrentPhonebookEntry->Name[tmp/2]='`'; //hides rest ot contents
3286       } else {
3287         if (MessageBuffer[6+tmp]==1) CurrentPhonebookEntry->Name[tmp]='~'; //enables/disables blinking
3288         if (MessageBuffer[6+tmp]==0) CurrentPhonebookEntry->Name[tmp]='`'; //hides rest ot contents
3289       }
3290     }
3291
3292     i=7+count;
3293     count=MessageBuffer[6+count];
3294
3295 #ifdef DEBUG
3296     fprintf(stdout, _("   Number: "));
3297
3298     for (tmp=0; tmp <count; tmp++)
3299       fprintf(stdout, "%c", MessageBuffer[i+tmp]);
3300
3301     fprintf(stdout, "\n");
3302 #endif /* DEBUG */
3303
3304     memcpy(CurrentPhonebookEntry->Number, MessageBuffer + i, count);
3305     CurrentPhonebookEntry->Number[count] = 0x00;
3306     CurrentPhonebookEntry->Group = MessageBuffer[i+count];
3307       
3308     /* Phone doesn't have entended phonebook */
3309     CurrentPhonebookEntry->SubEntriesCount = 0;
3310
3311     /* But for these memories data is saved and we can save it using 7110/6210 style */
3312     if (CurrentPhonebookEntry->MemoryType==GMT_DC ||
3313         CurrentPhonebookEntry->MemoryType==GMT_RC ||
3314         CurrentPhonebookEntry->MemoryType==GMT_MC) {
3315         CurrentPhonebookEntry->SubEntriesCount = 1;
3316         CurrentPhonebookEntry->SubEntries[0].EntryType=N7110_ENTRYTYPE_DATE;
3317         CurrentPhonebookEntry->SubEntries[0].NumberType=0;
3318         CurrentPhonebookEntry->SubEntries[0].BlockNumber=1;
3319         DecodeDateTime(MessageBuffer+(i+count+2),&CurrentPhonebookEntry->SubEntries[0].data.Date);
3320
3321 #ifdef DEBUG
3322       fprintf(stdout, _("   Date: "));
3323       fprintf(stdout, "%02u.%02u.%04u\n",
3324           CurrentPhonebookEntry->SubEntries[0].data.Date.Day,
3325           CurrentPhonebookEntry->SubEntries[0].data.Date.Month,
3326           CurrentPhonebookEntry->SubEntries[0].data.Date.Year);
3327       fprintf(stdout, _("   Time: "));
3328       fprintf(stdout, "%02u:%02u:%02u\n",
3329           CurrentPhonebookEntry->SubEntries[0].data.Date.Hour,
3330           CurrentPhonebookEntry->SubEntries[0].data.Date.Minute,
3331           CurrentPhonebookEntry->SubEntries[0].data.Date.Second);
3332 #endif /* DEBUG */
3333
3334       /* These values are set, when date and time unavailable in phone.
3335          Values from 3310 - in other can be different */
3336       if (CurrentPhonebookEntry->SubEntries[0].data.Date.Day==20 &&
3337           CurrentPhonebookEntry->SubEntries[0].data.Date.Month==1 &&
3338           CurrentPhonebookEntry->SubEntries[0].data.Date.Year==2118 &&
3339           CurrentPhonebookEntry->SubEntries[0].data.Date.Hour==3 &&
3340           CurrentPhonebookEntry->SubEntries[0].data.Date.Minute==14 &&
3341           CurrentPhonebookEntry->SubEntries[0].data.Date.Second==7)
3342           CurrentPhonebookEntry->SubEntriesCount = 0;
3343     }
3344
3345     /* Signal no error to calling code. */
3346     CurrentPhonebookError = GE_NONE;
3347
3348     break;
3349
3350   case 0x03:
3351
3352 #ifdef DEBUG
3353     fprintf(stdout, _("Message: Phonebook read entry error received:\n"));
3354 #endif /* DEBUG */
3355
3356     switch (MessageBuffer[4]) {
3357
3358       case 0x7d:
3359 #ifdef DEBUG
3360         fprintf(stdout, _("   Invalid memory type!\n"));
3361 #endif /* DEBUG */
3362         CurrentPhonebookError = GE_INVALIDMEMORYTYPE;
3363         break;
3364
3365       default:
3366 #ifdef DEBUG
3367         fprintf(stdout, _("   Unknown error!\n"));
3368 #endif /* DEBUG */
3369         CurrentPhonebookError = GE_INTERNALERROR;
3370     }
3371
3372     break;
3373
3374   }
3375 }
3376
3377 /* Routine to get specifed phone book location.  Designed to be called by
3378    application.  Will block until location is retrieved or a timeout/error
3379    occurs. */
3380 GSM_Error N6110_GetMemoryLocation(GSM_PhonebookEntry *entry)
3381 {
3382   unsigned char req[] = {N6110_FRAME_HEADER, 0x01, 0x00, 0x00, 0x00};
3383
3384   CurrentPhonebookEntry = entry;
3385
3386   req[4] = N6110_GetMemoryType(entry->MemoryType);
3387   req[5] = entry->Location;
3388
3389   return NULL_SendMessageSequence
3390     (50, &CurrentPhonebookError, 7, 0x03, req);
3391 }
3392
3393 static void N6110_ReplyWritePhonebookLocation(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3394
3395   switch (MessageBuffer[3]) {
3396
3397   case 0x05:
3398
3399 #ifdef DEBUG
3400     fprintf(stdout, _("Message: Phonebook written correctly.\n"));
3401 #endif /* DEBUG */
3402     CurrentPhonebookError = GE_NONE;
3403     break;
3404
3405   case 0x06:
3406
3407     switch (MessageBuffer[4]) {
3408       /* FIXME: other errors? When I send the phonebook with index of 350 it
3409          still report error 0x7d :-( */
3410       case 0x7d:
3411 #ifdef DEBUG
3412         fprintf(stdout, _("Message: Phonebook not written - name is too long.\n"));
3413 #endif /* DEBUG */
3414         CurrentPhonebookError = GE_PHBOOKNAMETOOLONG;
3415         break;
3416
3417       default:
3418 #ifdef DEBUG
3419         fprintf(stdout, _("   Unknown error!\n"));
3420 #endif /* DEBUG */
3421         CurrentPhonebookError = GE_INTERNALERROR;
3422     }
3423   }
3424 }
3425
3426 /* Routine to write phonebook location in phone. Designed to be called by
3427    application code. Will block until location is written or timeout
3428    occurs. */
3429 GSM_Error N6110_WritePhonebookLocation(GSM_PhonebookEntry *entry)
3430 {
3431   unsigned char req[128] = { N6110_FRAME_HEADER, 0x04, 0x00, 0x00 };
3432   int i=0, current=0;
3433
3434   req[4] = N6110_GetMemoryType(entry->MemoryType);
3435   req[5] = entry->Location;
3436
3437   current=7;
3438
3439   if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {
3440
3441      req[6] = strlen(entry->Name)*2;
3442
3443      EncodeUnicode (req+current,entry->Name ,strlen(entry->Name));
3444      
3445      for (i=0; i<strlen(entry->Name); i++)
3446      {
3447        /* here we encode "special" chars */
3448        if (entry->Name[i]=='~') req[current+i*2]=1; //enables/disables blinking
3449        if (entry->Name[i]=='`') req[current+i*2]=0; //hides rest ot contents
3450      }
3451
3452      current+=strlen(entry->Name)*2;
3453   } else {
3454
3455     req[6] = strlen(entry->Name);
3456
3457     for (i=0; i<strlen(entry->Name); i++)
3458     {
3459       req[current+i] = entry->Name[i];
3460
3461       /* here we encode "special" chars */
3462       if (entry->Name[i]=='~') req[current+i]=1; //enables/disables blinking
3463       if (entry->Name[i]=='`') req[current+i]=0; //hides rest ot contents
3464     }
3465
3466     current+=strlen(entry->Name);
3467   }
3468
3469   req[current++]=strlen(entry->Number);
3470
3471   for (i=0; i<strlen(entry->Number); i++)
3472     req[current+i] = entry->Number[i];
3473
3474   current+=strlen(entry->Number);
3475
3476   /* Jano: This allow to save 14 characters name into SIM memory, when
3477      No Group is selected. */
3478   if (entry->Group == 5)
3479     req[current++]=0xff;
3480   else
3481     req[current++]=entry->Group;
3482
3483   return NULL_SendMessageSequence
3484     (50, &CurrentPhonebookError, current, 0x03, req);
3485 }
3486
3487 #ifndef UCLINUX
3488
3489 void N6110_ReplyNetmonitor(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3490
3491   switch(MessageBuffer[3]) {
3492
3493     case 0x00:
3494 #ifdef DEBUG
3495       fprintf(stdout, _("Message: Netmonitor correctly set.\n"));
3496 #endif /* DEBUG */
3497       CurrentNetmonitorError=GE_NONE;  
3498       break;
3499       
3500     default:
3501 #ifdef DEBUG
3502       fprintf(stdout, _("Message: Netmonitor menu %d received:\n"), MessageBuffer[3]);
3503       fprintf(stdout, "%s\n", MessageBuffer+4);
3504 #endif /* DEBUG */
3505
3506       strcpy(CurrentNetmonitor, MessageBuffer+4);
3507
3508       CurrentNetmonitorError=GE_NONE;  
3509   }
3510 }
3511
3512 GSM_Error N6110_NetMonitor(unsigned char mode, char *Screen)
3513 {
3514   unsigned char req[] = { 0x00, 0x01, 0x7e, 0x00 };
3515   
3516   GSM_Error error;
3517   
3518   error=N6110_EnableExtendedCommands(0x01);
3519   if (error!=GE_NONE) return error;
3520
3521   CurrentNetmonitor=Screen;
3522
3523   req[3]=mode;
3524
3525   return NULL_SendMessageSequence
3526     (20, &CurrentNetmonitorError, 4, 0x40, req);
3527 }
3528
3529 /* Doesn't work in N3210. */
3530 /* In other allow to access phone menu without SIM card (just send any sequence) */
3531 GSM_Error N6110_SendDTMF(char *String)
3532 {
3533   unsigned char req[64] = { N6110_FRAME_HEADER, 0x50,
3534                             0x00 /* Length of DTMF string. */
3535                           };
3536                           
3537   u8 length=strlen(String);
3538
3539   if (length>59) length=59;
3540   
3541   req[4] = length;
3542   
3543   memcpy(req+5,String,length);
3544
3545   return NULL_SendMessageSequence
3546     (20, &CurrentSendDTMFError, 5+length, 0x01, req);
3547 }
3548
3549 void N6110_ReplyGetSpeedDial(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3550
3551   switch (MessageBuffer[3]) {
3552
3553   case 0x17:
3554
3555     switch (MessageBuffer[4]) {
3556       case 0x02: CurrentSpeedDialEntry->MemoryType = GMT_ME;
3557       default  : CurrentSpeedDialEntry->MemoryType = GMT_SM;
3558     }
3559       
3560     CurrentSpeedDialEntry->Location = MessageBuffer[5];
3561
3562 #ifdef DEBUG
3563     fprintf(stdout, _("Message: Speed dial entry received:\n"));
3564     fprintf(stdout, _("   Location: %d\n"), CurrentSpeedDialEntry->Location);
3565     fprintf(stdout, _("   MemoryType: %s\n"), N6110_MemoryType_String[CurrentSpeedDialEntry->MemoryType]);
3566     fprintf(stdout, _("   Number: %d\n"), CurrentSpeedDialEntry->Number);
3567 #endif /* DEBUG */
3568
3569     CurrentSpeedDialError=GE_NONE;
3570     break;
3571
3572   case 0x18:
3573
3574 #ifdef DEBUG
3575     fprintf(stdout, _("Message: Speed dial entry error\n"));
3576 #endif /* DEBUG */
3577     CurrentSpeedDialError=GE_INVALIDSPEEDDIALLOCATION;
3578     break;
3579
3580   }
3581 }
3582
3583 GSM_Error N6110_GetSpeedDial(GSM_SpeedDial *entry)
3584 {
3585
3586   unsigned char req[] = { N6110_FRAME_HEADER,
3587                           0x16,
3588                           0x00  /* The number of speed dial. */
3589                         };
3590
3591   CurrentSpeedDialEntry = entry;
3592
3593   req[4] = entry->Number;
3594
3595   return NULL_SendMessageSequence
3596     (20, &CurrentSpeedDialError, 5, 0x03, req);
3597 }
3598
3599 void N6110_ReplySetSpeedDial(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3600
3601   switch (MessageBuffer[3]) {
3602
3603   case 0x1a:
3604
3605 #ifdef DEBUG
3606     fprintf(stdout, _("Message: Speed dial entry set.\n"));
3607 #endif /* DEBUG */
3608     CurrentSpeedDialError=GE_NONE;
3609     break;
3610
3611   case 0x1b:
3612
3613 #ifdef DEBUG
3614     fprintf(stdout, _("Message: Speed dial entry setting error.\n"));
3615 #endif /* DEBUG */
3616     CurrentSpeedDialError=GE_INVALIDSPEEDDIALLOCATION;
3617     break;
3618
3619   }
3620 }
3621
3622 GSM_Error N6110_SetSpeedDial(GSM_SpeedDial *entry)
3623 {
3624
3625   unsigned char req[] = { N6110_FRAME_HEADER,
3626                           0x19,
3627                           0x00, /* Number */
3628                           0x00, /* Memory Type */
3629                           0x00  /* Location */
3630                         };
3631
3632   req[4] = entry->Number;
3633
3634   switch (entry->MemoryType) {
3635     case GMT_ME: req[5] = 0x02;
3636     default    : req[5] = 0x03;
3637   }
3638
3639   req[6] = entry->Location;
3640
3641   return NULL_SendMessageSequence
3642     (20, &CurrentSpeedDialError, 7, 0x03, req);
3643 }
3644
3645 /* This function finds parts of SMS in frame used in new Nokia phones
3646    in internal protocols (they're coded according to GSM 03.40), copies them
3647    to GSM_ETSISMSMessage and calls GSM_DecodeETSISMS to decode
3648    GSM_ETSISMSMessage to GSM_SMSMessage structure */
3649 GSM_Error GSM_DecodeNokiaSMSFrame(GSM_SMSMessage *SMS, unsigned char *req, int length)
3650 {
3651   SMS_MessageType PDU=SMS_Deliver;
3652   GSM_ETSISMSMessage ETSI;
3653   int offset=0,i;
3654
3655   ETSI.firstbyte=req[12];
3656
3657   /* See GSM 03.40 section 9.2.3.1 */
3658   if ((ETSI.firstbyte & 0x03) == 0x01) PDU=SMS_Submit;
3659   if ((ETSI.firstbyte & 0x03) == 0x02) PDU=SMS_Status_Report;
3660
3661   switch (PDU) {
3662     case SMS_Submit       : offset=5;break;
3663     case SMS_Deliver      : offset=4;break;
3664     case SMS_Status_Report: offset=3;break;
3665     default:                break;
3666   }
3667
3668   for (i=0;i<req[0]+1;i++)
3669     ETSI.SMSCNumber[i]=req[i];
3670
3671   for (i=0;i<((req[12+offset]+1)/2+1)+1;i++)
3672     ETSI.Number[i]=req[i+12+offset];
3673
3674   switch (PDU) {
3675     case SMS_Submit:
3676       ETSI.TPDCS=req[10+offset];
3677       ETSI.TPUDL=req[11+offset];
3678       ETSI.TPVP=0;  //no support for now
3679       ETSI.TPPID=0; //no support for now
3680       for(i=31+offset;i<length;i++)
3681         ETSI.MessageText[i-31-offset]=req[i];
3682       break;
3683     case SMS_Deliver:
3684       ETSI.TPDCS=req[10+offset];
3685       ETSI.TPUDL=req[11+offset];
3686       ETSI.TPPID=0; //no support for now
3687       for(i=31+offset;i<length;i++)
3688         ETSI.MessageText[i-31-offset]=req[i];
3689       for(i=0;i<7;i++)
3690         ETSI.DeliveryDateTime[i]=req[i+24+offset];
3691       break;
3692     case SMS_Status_Report:
3693       for(i=0;i<7;i++)
3694         ETSI.DeliveryDateTime[i]=req[i+24+offset];
3695       ETSI.TPStatus=req[14];
3696       for(i=0;i<7;i++)
3697         ETSI.SMSCDateTime[i]=req[i+34];
3698       break;
3699     default:
3700       break;
3701   }
3702
3703   GSM_DecodeETSISMS(SMS, &ETSI);
3704
3705   SMS->Name[0]=0;
3706
3707   return GE_NONE;
3708 }
3709
3710 void N6110_ReplyGetSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3711
3712   int offset;
3713   
3714   switch (MessageBuffer[3]) {
3715
3716   case 0x08:
3717
3718     switch (MessageBuffer[7]) {
3719
3720       case 0x00:
3721         CurrentSMSMessage->Type = GST_SMS;
3722         CurrentSMSMessage->folder=GST_INBOX;
3723         offset=4;
3724         break;
3725
3726       case 0x01:
3727         CurrentSMSMessage->Type = GST_DR;
3728         CurrentSMSMessage->folder=GST_INBOX;
3729         offset=3;
3730         break;
3731
3732       case 0x02:
3733         CurrentSMSMessage->Type = GST_SMS;
3734         CurrentSMSMessage->folder=GST_OUTBOX;
3735         offset=5;
3736         break;
3737
3738       default:
3739         CurrentSMSMessage->Type = GST_UN;
3740         offset=4;
3741         break;
3742
3743     }
3744
3745     /* Field Short Message Status - MessageBuffer[4] seems not to be
3746        compliant with GSM 07.05 spec.
3747        Meaning     Nokia protocol       GMS spec
3748        ----------------------------------------------------
3749        MO Sent     0x05                 0x07 or 0x01
3750        MO Not sent 0x07                 0x06 or 0x00
3751        MT Read     0x01                 0x05 or 0x01
3752        MT Not read 0x03                 0x04 or 0x00
3753        ----------------------------------------------------
3754        See GSM 07.05 section 2.5.2.6 and correct me if I'm wrong.
3755        
3756                                          Pawel Kot */
3757
3758     if (MessageBuffer[4] & 0x02) CurrentSMSMessage->Status = GSS_NOTSENTREAD;
3759                             else CurrentSMSMessage->Status = GSS_SENTREAD;
3760
3761 #ifdef DEBUG
3762     fprintf(stdout, _("Number: %d\n"), MessageBuffer[6]);
3763
3764     if (CurrentSMSMessage->folder!=1) { //GST_OUTBOX
3765       fprintf(stdout, _("Message: Received SMS (mobile terminated)\n"));
3766     } else {
3767       fprintf(stdout, _("Message: Outbox message (mobile originated)\n"));
3768     }
3769
3770     if (CurrentSMSMessage->Type == GST_DR) fprintf(stdout, _("   Delivery Report\n"));
3771     if (CurrentSMSMessage->Type == GST_UN) fprintf(stdout, _("   Unknown type\n"));
3772
3773     if (CurrentSMSMessage->folder==1) { //GST_OUTBOX
3774       if (CurrentSMSMessage->Status) fprintf(stdout, _("   Sent\n"));
3775                                 else fprintf(stdout, _("   Not sent\n"));
3776     } else {
3777       if (CurrentSMSMessage->Status) fprintf(stdout, _("   Read\n"));
3778                                 else fprintf(stdout, _("   Not read\n"));
3779     }
3780 #endif
3781
3782     CurrentSMSPointer=GSM_DecodeNokiaSMSFrame(CurrentSMSMessage, MessageBuffer+8, MessageLength-8);
3783
3784     CurrentSMSMessage->MemoryType = MessageBuffer[5];
3785     CurrentSMSMessage->MessageNumber = MessageBuffer[6];
3786  
3787     /* Signal no error to calling code. */
3788     CurrentSMSMessageError = GE_NONE;
3789
3790 #ifdef DEBUG
3791     fprintf(stdout, "\n");
3792 #endif
3793
3794     break;
3795
3796   case 0x09:
3797
3798     /* We have requested invalid or empty location. */
3799
3800 #ifdef DEBUG
3801     fprintf(stdout, _("Message: SMS reading failed\n"));
3802
3803     switch (MessageBuffer[4]) {
3804       case 0x02:
3805         fprintf(stdout, _("   Invalid location!\n"));break;
3806       case 0x07:
3807         fprintf(stdout, _("   Empty SMS location.\n"));break;
3808       case 0x0c:
3809         fprintf(stdout, _("   No access to memory (no PIN on card ?)\n"));break;
3810       default:      
3811         fprintf(stdout, _("   Error code %i - please report it \n"),MessageBuffer[4]);break;
3812     }
3813 #endif /* DEBUG */
3814
3815     switch (MessageBuffer[4]) {
3816       case 0x02:CurrentSMSMessageError = GE_INVALIDSMSLOCATION;break;
3817       case 0x07:CurrentSMSMessageError = GE_EMPTYSMSLOCATION;break;
3818       case 0x0c:CurrentSMSMessageError = GE_NOACCESS;break;
3819       default  :CurrentSMSMessageError = GE_UNKNOWN;break;
3820     }
3821
3822     break;
3823
3824   }
3825 }
3826
3827 GSM_Error N6110_GetSMSMessage(GSM_SMSMessage *message)
3828 {
3829
3830   unsigned char req[] = { N6110_FRAME_HEADER,
3831                           0x07,
3832                           0x02, /* Unknown */
3833                           0x00, /* Location */
3834                           0x01, 0x64};
3835
3836   int timeout = 60;
3837
3838   /* State machine code writes data to these variables when it comes in. */
3839
3840   CurrentSMSMessage = message;
3841   CurrentSMSMessageError = GE_BUSY;
3842
3843   req[5] = message->Location;
3844
3845   /* Send request */
3846   Protocol->SendMessage(8, 0x02, req);
3847
3848   /* Wait for timeout or other error. */
3849   while (timeout != 0 && (CurrentSMSMessageError == GE_BUSY || CurrentSMSMessageError == GE_SMSWAITING)) {
3850
3851     if (--timeout == 0)
3852       return (GE_TIMEOUT);
3853
3854     usleep (100000);
3855   }
3856
3857   return (CurrentSMSMessageError);
3858 }
3859
3860 void N6110_ReplyDeleteSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3861
3862 #ifdef DEBUG
3863   fprintf(stdout, _("Message: SMS deleted successfully.\n"));
3864 #endif /* DEBUG */
3865
3866   CurrentSMSMessageError = GE_NONE;     
3867 }
3868
3869 GSM_Error N6110_DeleteSMSMessage(GSM_SMSMessage *message)
3870 {
3871   unsigned char req[] = {N6110_FRAME_HEADER, 0x0a, 0x02, 0x00};
3872
3873   req[5] = message->Location;
3874
3875   return NULL_SendMessageSequence
3876     (50, &CurrentSMSMessageError, 6, 0x14, req);
3877 }
3878
3879 /* FIXME: do we need more than SMS_Submit and SMS_Deliver ? */
3880 GSM_Error GSM_EncodeNokiaSMSFrame(GSM_SMSMessage *SMS, unsigned char *req, int *length, SMS_MessageType PDU)
3881 {
3882   GSM_ETSISMSMessage ETSI;