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