bd702853a3b77758bc2a1ff2793a3e58363e961c
[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, 0x00, /* SMS send request*/
3859   };
3860
3861   int length;
3862
3863   error=GSM_EncodeNokiaSMSFrame(SMS, req+6, &length, SMS_Submit);    
3864   if (error != GE_NONE) return error;
3865
3866   return NULL_SendMessageSequence
3867     (200, &CurrentSMSMessageError, 42+length, 0x02, req);
3868 }
3869
3870 void N6110_ReplySaveSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3871
3872   switch (MessageBuffer[3]) {
3873
3874   case 0x05:
3875       
3876 #ifdef DEBUG
3877     fprintf(stdout, _("SMS Message stored at %d\n"), MessageBuffer[5]);
3878 #endif
3879       
3880     CurrentSMSMessage->MessageNumber=MessageBuffer[5];
3881       
3882     CurrentSMSMessageError = GE_NONE;
3883     break;
3884
3885   case 0x06:
3886 #ifdef DEBUG
3887     fprintf(stdout, _("SMS saving failed\n"));
3888     switch (MessageBuffer[4]) {
3889       case 0x02:fprintf(stdout, _("   All locations busy.\n"));break;
3890       case 0x03:fprintf(stdout, _("   Invalid location!\n"));break;
3891       default  :fprintf(stdout, _("   Unknown error.\n"));break;
3892     }
3893 #endif      
3894       
3895     switch (MessageBuffer[4]) {
3896       case 0x02:CurrentSMSMessageError = GE_MEMORYFULL;break;
3897       case 0x03:CurrentSMSMessageError = GE_INVALIDSMSLOCATION;break;
3898       default  :CurrentSMSMessageError = GE_UNKNOWN;break;
3899     }
3900   }
3901 }
3902
3903 /* GST_DR and GST_UN not supported ! */
3904 GSM_Error N6110_SaveSMSMessage(GSM_SMSMessage *SMS)
3905 {
3906   unsigned char req[256] = {
3907     N6110_FRAME_HEADER, 0x04, /* SMS save request*/
3908     0x00, /* SMS Status. Different for Inbox and Outbox */
3909     0x02, /* ?? */
3910     0x00, /* SMS Location */
3911     0x02, /* SMS Type */
3912   };
3913
3914   int length;
3915   SMS_MessageType PDU;
3916   GSM_Error error;
3917
3918   if (SMS->Location) req[6] = SMS->Location;
3919     
3920   if (SMS->folder==0) { /*Inbox*/
3921     req[4]=1;      /* SMS Status */
3922     req[7] = 0x00; /* SMS Type */
3923     PDU=SMS_Deliver;
3924   } else {
3925     req[4]=5;      /* SMS Status */
3926     req[7] = 0x02; /* SMS Type */
3927     PDU=SMS_Submit;
3928   }
3929   
3930   if (SMS->Status == GSS_NOTSENTREAD) req[4] |= 0x02;  
3931
3932   error=GSM_EncodeNokiaSMSFrame(SMS, req+8, &length, PDU);  
3933   if (error != GE_NONE) return error;
3934
3935   CurrentSMSMessage = SMS;
3936
3937   return NULL_SendMessageSequence
3938     (70, &CurrentSMSMessageError, 39+length, 0x14, req);
3939 }
3940
3941 void N6110_ReplySetCellBroadcast(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3942
3943 #ifdef DEBUG
3944   fprintf(stdout, _("Message: Cell Broadcast enabled/disabled successfully.\n")); fflush (stdout);
3945 #endif
3946
3947   CurrentCBError = GE_NONE;
3948 }
3949
3950 /* Enable and disable Cell Broadcasting */
3951 GSM_Error N6110_EnableCellBroadcast(void)
3952 {
3953   unsigned char req[] = {N6110_FRAME_HEADER, 0x20,
3954                          0x01, 0x01, 0x00, 0x00, 0x01, 0x01};
3955
3956 #ifdef DEBUG
3957   fprintf (stdout,"Enabling CB\n");
3958 #endif
3959
3960   CurrentCBMessage = (GSM_CBMessage *)malloc(sizeof (GSM_CBMessage));
3961   CurrentCBMessage->Channel = 0;
3962   CurrentCBMessage->New = false;
3963   strcpy (CurrentCBMessage->Message,"");
3964
3965   return NULL_SendMessageSequence
3966     (10, &CurrentCBError, 10, 0x02, req);
3967 }
3968
3969
3970 GSM_Error N6110_DisableCellBroadcast(void)
3971 {
3972   /* Should work, but not tested fully */
3973
3974   unsigned char req[] = {N6110_FRAME_HEADER, 0x20,
3975                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /*VERIFY*/
3976
3977   return NULL_SendMessageSequence
3978     (10, &CurrentCBError, 10, 0x02, req);
3979 }
3980
3981 void N6110_ReplyReadCellBroadcast(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3982
3983   int i, tmp;
3984   unsigned char output[160];
3985   
3986   CurrentCBMessage->Channel = MessageBuffer[7];
3987   CurrentCBMessage->New = true;
3988   tmp=GSM_UnpackEightBitsToSeven(0, MessageBuffer[9], MessageBuffer[9], MessageBuffer+10, output);
3989
3990 #ifdef DEBUG
3991   fprintf(stdout, _("Message: CB received.\n")); fflush (stdout);
3992
3993   fprintf(stdout, _("Message: channel number %i\n"),MessageBuffer[7]);
3994
3995   fflush (stdout);
3996
3997   for (i=0; i<tmp;i++) {
3998     fprintf(stdout, "%c", DecodeWithDefaultAlphabet(output[i]));
3999   }
4000
4001   fprintf(stdout, "\n");
4002 #endif
4003    
4004   for (i=0; i<tmp; i++) {
4005     CurrentCBMessage->Message[i] = DecodeWithDefaultAlphabet(output[i]);
4006   }
4007   CurrentCBMessage->Message[i]=0;
4008 }
4009
4010 GSM_Error N6110_ReadCellBroadcast(GSM_CBMessage *Message)
4011 {
4012 #ifdef DEBUG
4013    fprintf(stdout,"Reading CB\n");
4014 #endif
4015
4016   if (CurrentCBMessage != NULL) 
4017   {
4018     if (CurrentCBMessage->New == true)
4019     {
4020 #ifdef DEBUG
4021   fprintf(stdout,"New CB received\n");
4022 #endif
4023       Message->Channel = CurrentCBMessage->Channel;
4024       strcpy(Message->Message,CurrentCBMessage->Message);
4025       CurrentCBMessage->New = false;
4026       return (GE_NONE);
4027     }
4028   }
4029   return (GE_NONEWCBRECEIVED);
4030 }
4031
4032 int N6110_MakeCallerGroupFrame(unsigned char *req,GSM_Bitmap Bitmap)
4033 {
4034   int count=0;
4035
4036   req[count++]=Bitmap.number;
4037   req[count++]=strlen(Bitmap.text);
4038   memcpy(req+count,Bitmap.text,req[count-1]);
4039   count+=req[count-1];
4040   req[count++]=Bitmap.ringtone;
4041
4042   /* Setting for graphic:
4043      0x00 - Off
4044      0x01 - On
4045      0x02 - View Graphics
4046      0x03 - Send Graphics
4047      0x04 - Send via IR
4048      You can even set it higher but Nokia phones (my
4049      6110 at least) will not show you the name of this
4050      item in menu ;-)) Nokia is really joking here. */
4051   if (Bitmap.enabled) req[count++]=0x01;
4052                  else req[count++]=0x00;
4053
4054   req[count++]=(Bitmap.size+4)>>8;
4055   req[count++]=(Bitmap.size+4)%0xff;
4056   req[count++]=0x00;  /* Future extensions! */
4057   req[count++]=Bitmap.width;
4058   req[count++]=Bitmap.height;
4059   req[count++]=0x01;  /* Just BW */
4060   memcpy(req+count,Bitmap.bitmap,Bitmap.size);
4061
4062   return count+Bitmap.size;
4063 }
4064
4065 int N6110_MakeOperatorLogoFrame(unsigned char *req,GSM_Bitmap Bitmap)
4066 {
4067   int count=0;
4068
4069   EncodeNetworkCode(req+count, Bitmap.netcode);
4070   count=count+3;
4071
4072   req[count++]=(Bitmap.size+4)>>8;
4073   req[count++]=(Bitmap.size+4)%0xff;
4074   req[count++]=0x00;  /* Infofield */
4075   req[count++]=Bitmap.width;
4076   req[count++]=Bitmap.height;
4077   req[count++]=0x01;  /* Just BW */    
4078   memcpy(req+count,Bitmap.bitmap,Bitmap.size);
4079
4080   return count+Bitmap.size;
4081 }
4082
4083 int N6110_MakeStartupLogoFrame(unsigned char *req,GSM_Bitmap Bitmap)
4084 {
4085   int count=0;
4086
4087   req[count++]=0x01;
4088   req[count++]=Bitmap.height;
4089   req[count++]=Bitmap.width;
4090   memcpy(req+count,Bitmap.bitmap,Bitmap.size);
4091
4092   return count+Bitmap.size;
4093 }
4094
4095 /* Set a bitmap or welcome-note */
4096 GSM_Error N6110_SetBitmap(GSM_Bitmap *Bitmap) {
4097
4098   unsigned char req[600] = { N6110_FRAME_HEADER };
4099   u16 count=3;
4100   u8 textlen;
4101   
4102   int timeout=50;
4103
4104   /* Direct uploading variables */
4105   GSM_MultiSMSMessage SMS;
4106   unsigned char buffer[1000] = {0x0c,0x01};
4107   GSM_NetworkInfo NetworkInfo;
4108
4109   GSM_Error error;
4110  
4111   /* Uploading with preview */
4112   if (Bitmap->number==255 &&
4113      (Bitmap->type==GSM_OperatorLogo || Bitmap->type==GSM_CallerLogo)) {
4114     GSM_SaveBitmapToSMS(&SMS,Bitmap,false,false);
4115     memcpy(buffer+2,SMS.SMS[0].UDH,SMS.SMS[0].UDH[0]+1);
4116
4117     memcpy(buffer+2+SMS.SMS[0].UDH[0]+1,SMS.SMS[0].MessageText,SMS.SMS[0].Length);
4118
4119     buffer[2+SMS.SMS[0].UDH[0]+1+SMS.SMS[0].Length]=0x00;
4120
4121     Protocol->SendMessage(2+SMS.SMS[0].UDH[0]+1+SMS.SMS[0].Length+1, 0x12, buffer);
4122
4123     GSM->GetNetworkInfo(&NetworkInfo); //need to make something
4124     return GE_NONE; //no answer from phone
4125   }
4126  
4127   CurrentSetBitmapError = GE_BUSY;  
4128   
4129   switch (Bitmap->type) {
4130   case GSM_WelcomeNoteText:
4131   case GSM_DealerNoteText:
4132     req[count++]=0x18;
4133     req[count++]=0x01; /* Only one block */
4134
4135     if (Bitmap->type==GSM_WelcomeNoteText)
4136       req[count++]=0x02; /* Welcome text */
4137     else
4138       req[count++]=0x03; /* Dealer Welcome Note */
4139
4140     textlen=strlen(Bitmap->text);
4141     req[count++]=textlen;
4142     memcpy(req+count,Bitmap->text,textlen);
4143       
4144     count+=textlen;
4145
4146     Protocol->SendMessage(count, 0x05, req);
4147     
4148     break;
4149
4150   case GSM_StartupLogo:
4151     if (Bitmap->number==0) {
4152
4153       /* For 33xx we first set animated logo to default */
4154       if (GetModelFeature (FN_STARTUP)==F_STANIM) {
4155         error=N6110_SetProfileFeature(0, 0x29, Bitmap->number);
4156         if (error!=GE_NONE) return error;
4157       }
4158
4159       req[count++]=0x18;
4160       req[count++]=0x01; /* Only one block */
4161       count=count+N6110_MakeStartupLogoFrame(req+5,*Bitmap); 
4162       Protocol->SendMessage(count, 0x05, req);
4163     } else {
4164       return N6110_SetProfileFeature(0, 0x29, Bitmap->number);
4165     }
4166     break;
4167
4168   case GSM_OperatorLogo:
4169     req[count++]=0x30;  /* Store Op Logo */
4170     req[count++]=0x01;  /* Location */
4171     count=count+N6110_MakeOperatorLogoFrame(req+5,*Bitmap); 
4172     Protocol->SendMessage(count, 0x05, req);
4173     break;
4174
4175   case GSM_CallerLogo:
4176     req[count++]=0x13;
4177     count=count+N6110_MakeCallerGroupFrame(req+4,*Bitmap);
4178     Protocol->SendMessage(count, 0x03, req);
4179     break;
4180
4181   case GSM_PictureImage:
4182     req[count++]=0x03;
4183     req[count++]=Bitmap->number;
4184     if (strcmp(Bitmap->Sender,"")) {
4185        req[count]=GSM_PackSemiOctetNumber(Bitmap->Sender, req+count+1,true);
4186
4187        /* Convert number of semioctets to number of chars and add count */
4188        textlen=req[count];
4189        if (textlen % 2) textlen++;
4190        count+=textlen / 2 + 1;
4191
4192        count++;
4193     } else {
4194       req[count++]=0x00;
4195       req[count++]=0x00;
4196     }
4197     req[count++]=0x00;
4198     req[count++]=strlen(Bitmap->text);
4199     memcpy(req+count,Bitmap->text,strlen(Bitmap->text));
4200     count+=strlen(Bitmap->text);
4201     req[count++]=0x00;
4202     req[count++]=Bitmap->width;
4203     req[count++]=Bitmap->height;
4204     req[count++]=0x01;
4205     memcpy(req+count,Bitmap->bitmap,Bitmap->size);
4206     Protocol->SendMessage(count+Bitmap->size, 0x47, req);
4207     break;
4208
4209   case GSM_7110OperatorLogo:
4210   case GSM_7110StartupLogo:
4211   case GSM_6210StartupLogo:
4212     return GE_NOTSUPPORTED;
4213
4214   case GSM_None:
4215     return GE_NONE;
4216   }
4217
4218   /* Wait for timeout or other error. */
4219   while (timeout != 0 && CurrentSetBitmapError == GE_BUSY ) {
4220           
4221     if (--timeout == 0)
4222       return (GE_TIMEOUT);
4223                     
4224     usleep (100000);
4225   }
4226
4227   return CurrentSetBitmapError;
4228 }
4229
4230 /* Get a bitmap from the phone */
4231 GSM_Error N6110_GetBitmap(GSM_Bitmap *Bitmap) {
4232
4233   unsigned char req[10] = { N6110_FRAME_HEADER };
4234   u8 count=3;
4235   
4236   int timeout=100;
4237   
4238   CurrentGetBitmap=Bitmap; 
4239   CurrentGetBitmapError = GE_BUSY;  
4240   
4241   switch (CurrentGetBitmap->type) {
4242   case GSM_StartupLogo:
4243   case GSM_WelcomeNoteText:
4244   case GSM_DealerNoteText:
4245     req[count++]=0x16;
4246     Protocol->SendMessage(count, 0x05, req);
4247     break;
4248   case GSM_OperatorLogo:
4249     req[count++]=0x33;
4250     req[count++]=0x01; /* Location 1 */
4251     Protocol->SendMessage(count, 0x05, req);
4252     break;
4253   case GSM_CallerLogo:
4254     req[count++]=0x10;
4255     req[count++]=Bitmap->number;
4256     Protocol->SendMessage(count, 0x03, req);
4257     break;
4258   case GSM_PictureImage:
4259     req[count++]=0x01;
4260     req[count++]=Bitmap->number;
4261     Protocol->SendMessage(count, 0x47, req);
4262     break;
4263   case GSM_7110OperatorLogo:
4264   case GSM_7110StartupLogo:
4265   case GSM_6210StartupLogo:
4266   default:
4267     return GE_NOTSUPPORTED;
4268   }
4269
4270   /* Wait for timeout or other error. */
4271   while (timeout != 0 && CurrentGetBitmapError == GE_BUSY ) {
4272           
4273     if (--timeout == 0)
4274       return (GE_TIMEOUT);
4275                     
4276     usleep (100000);
4277   }
4278
4279   CurrentGetBitmap=NULL;
4280
4281   return CurrentGetBitmapError;
4282 }
4283
4284 void N6110_ReplySetRingtone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4285
4286   switch (MessageBuffer[3]) {
4287
4288   /* Set ringtone OK */
4289   case 0x37:       
4290 #ifdef DEBUG
4291     fprintf(stdout, _("Message: Ringtone set OK!\n"));
4292 #endif  
4293     CurrentRingtoneError=GE_NONE; 
4294     break;      
4295
4296   /* Set ringtone error */
4297   case 0x38:       
4298 #ifdef DEBUG
4299     fprintf(stdout, _("Message: Ringtone setting error !\n"));
4300 #endif  
4301     CurrentRingtoneError=GE_NOTSUPPORTED; 
4302     break;      
4303   }
4304 }
4305
4306 GSM_Error N6110_SetRingTone(GSM_Ringtone *ringtone, int *maxlength)
4307 {
4308   
4309   char req[FB61_MAX_RINGTONE_FRAME_LENGTH+10] =
4310       {N6110_FRAME_HEADER,
4311        0x36,
4312        0x00,  /* Location */
4313        0x00,0x78};
4314
4315   int size=FB61_MAX_RINGTONE_FRAME_LENGTH;
4316  
4317   /* Variables for preview uploading */
4318   unsigned char buffer[FB61_MAX_RINGTONE_FRAME_LENGTH+50];
4319   unsigned char buffer2[20];
4320   GSM_NetworkInfo NetworkInfo;
4321
4322   /* Setting ringtone with preview */
4323   if (ringtone->location==255) {
4324     buffer[0]=0x0c;
4325     buffer[1]=0x01;
4326     EncodeUDHHeader(buffer2, GSM_RingtoneUDH);
4327     memcpy(buffer+2,buffer2,buffer2[0]+1); //copying UDH
4328     *maxlength=GSM_PackRingtone(ringtone, buffer+2+buffer2[0]+1, &size); //packing ringtone
4329     Protocol->SendMessage(2+buffer2[0]+1+size, 0x12, buffer); //sending frame
4330     GSM->GetNetworkInfo(&NetworkInfo); //need to make something
4331     sleep(1);
4332     return GE_NONE; //no answer from phone
4333   }
4334   
4335   *maxlength=GSM_PackRingtone(ringtone, req+7, &size);
4336
4337   req[4]=ringtone->location-1;
4338
4339   return NULL_SendMessageSequence
4340     (50, &CurrentRingtoneError, (size+7), 0x05, req);
4341 }
4342
4343 void N6110_ReplyGetBinRingtone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4344
4345   int i;
4346   
4347   switch (MessageBuffer[4]) {
4348     case 0x00: /* location supported. We have ringtone */
4349
4350       /* Binary format used in N6150 */
4351       if (MessageBuffer[5]==0x0c && MessageBuffer[6]==0x01 && MessageBuffer[7]==0x2c) {
4352 #ifdef DEBUG
4353         fprintf(stdout,_("Message: ringtone \""));
4354 #endif      
4355
4356         /* Copying name */
4357         i=8;
4358         while (true) {
4359 #ifdef DEBUG
4360           if (MessageBuffer[i]!=0)
4361             fprintf(stdout,_("%c"),MessageBuffer[i]);
4362 #endif
4363           CurrentGetBinRingtone->name[i-8]=MessageBuffer[i];
4364           if (MessageBuffer[i]==0) break;
4365           i++;
4366         }
4367
4368 #ifdef DEBUG    
4369         fprintf(stdout,_("\" received from location %i\n"),MessageBuffer[3]+1);
4370 #endif
4371       
4372         /* Looking for end */
4373         i=0;
4374         while (true) {
4375           if (MessageBuffer[i]==0x07 && MessageBuffer[i+1]==0x0b) {
4376             i=i+2;break;
4377           }
4378           if (MessageBuffer[i]==0x0e && MessageBuffer[i+1]==0x0b) {
4379             i=i+2;break;
4380           }
4381           i++;
4382           if (i==MessageLength) break;
4383         }
4384           
4385         /* Copying frame */
4386         memcpy(CurrentGetBinRingtone->frame,MessageBuffer+3,i-3);
4387         CurrentGetBinRingtone->length=i-3;
4388       
4389         CurrentBinRingtoneError=GE_NONE;
4390         break;
4391       }
4392           
4393       /* Binary format used in N3210 */
4394       if (MessageBuffer[5]==0x10 && MessageBuffer[6]==0x01 && MessageBuffer[7]==0x2c) {      
4395
4396 #ifdef DEBUG
4397         fprintf(stdout,_("Message: ringtone \""));
4398 #endif      
4399
4400         /* Copying name */
4401         i=8;
4402         while (true) {
4403 #ifdef DEBUG
4404           if (MessageBuffer[i]!=0)
4405             fprintf(stdout,_("%c"),MessageBuffer[i]);
4406 #endif
4407           CurrentGetBinRingtone->name[i-8]=MessageBuffer[i];
4408           if (MessageBuffer[i]==0) break;
4409           i++;
4410         }
4411
4412 #ifdef DEBUG    
4413         fprintf(stdout,_("\" received from location %i\n"),MessageBuffer[3]+1);
4414 #endif
4415
4416         /* Here changes to get full compatibility with binary format used in N6150 */
4417         MessageBuffer[3]=0;
4418         MessageBuffer[4]=0;
4419         MessageBuffer[5]=0x0c;
4420         MessageBuffer[6]=0x01;
4421         MessageBuffer[7]=0x2c;
4422
4423         /* Looking for end */
4424         i=0;
4425         while (true) {
4426           if (MessageBuffer[i]==0x07 && MessageBuffer[i+1]==0x0b) {
4427             i=i+2;break;
4428           }
4429           if (MessageBuffer[i]==0x0e && MessageBuffer[i+1]==0x0b) {
4430             i=i+2;break;
4431           }
4432           i++;
4433           if (i==MessageLength) break;
4434         }
4435           
4436         /* Copying frame */
4437         memcpy(CurrentGetBinRingtone->frame,MessageBuffer+3,i-3);
4438
4439         CurrentGetBinRingtone->length=i-3;
4440             
4441         CurrentBinRingtoneError=GE_NONE;          
4442         break;
4443       }
4444
4445       /* Copying frame */
4446       memcpy(CurrentGetBinRingtone->frame,MessageBuffer,MessageLength);
4447
4448       CurrentGetBinRingtone->length=MessageLength;
4449
4450 #ifdef DEBUG    
4451       fprintf(stdout,_("Message: unknown binary format for ringtone received from location %i\n"),MessageBuffer[3]+1);
4452 #endif
4453       CurrentBinRingtoneError=GE_UNKNOWNMODEL;
4454       break;
4455
4456     default:
4457
4458 #ifdef DEBUG
4459       fprintf(stdout,_("Message: Phone doesn't support downloaded ringtones at location %i\n"),MessageBuffer[3]+1);
4460 #endif
4461
4462       CurrentBinRingtoneError=GE_INVALIDRINGLOCATION;  
4463   }
4464 }
4465
4466 GSM_Error N6110_GetBinRingTone(GSM_BinRingtone *ringtone)
4467 {
4468   unsigned char req[] = { 0x00,0x01,0x9e,
4469                           0x00 }; //location
4470
4471   GSM_Error error;
4472   
4473   CurrentGetBinRingtone=ringtone;
4474   
4475   error=N6110_EnableExtendedCommands(0x01);
4476   if (error!=GE_NONE) return error;
4477
4478   req[3]=ringtone->location-1;
4479   
4480   return NULL_SendMessageSequence
4481     (50, &CurrentBinRingtoneError, 4, 0x40, req);
4482 }
4483
4484 void N6110_ReplySetBinRingtone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4485
4486   switch (MessageBuffer[4]) {
4487     case 0x00: /* location supported. We set ringtone */
4488 #ifdef DEBUG
4489       fprintf(stdout,_("Message: downloaded ringtone set at location %i\n"),MessageBuffer[3]+1);
4490 #endif
4491       CurrentBinRingtoneError=GE_NONE;
4492       break;
4493
4494     default:
4495 #ifdef DEBUG
4496       fprintf(stdout,_("Message: Phone doesn't support downloaded ringtones at location %i\n"),MessageBuffer[3]+1);
4497 #endif
4498       CurrentBinRingtoneError=GE_NOTSUPPORTED;    
4499       break;
4500   }
4501 }
4502
4503 GSM_Error N6110_SetBinRingTone(GSM_BinRingtone *ringtone)
4504 {
4505   unsigned char req[1000] = { 0x00,0x01,0xa0};
4506
4507   GSM_Error error;
4508
4509   GSM_BinRingtone ring;
4510
4511   /* Must be sure, that can upload ringtone to this phone */
4512   ring.location=ringtone->location;
4513   error=N6110_GetBinRingTone(&ring);
4514   if (error!=GE_NONE) return error;
4515     
4516   error=N6110_EnableExtendedCommands(0x01);
4517   if (error!=GE_NONE) return error;
4518   
4519   memcpy(req+3,ringtone->frame,ringtone->length);
4520
4521   req[3]=ringtone->location-1;
4522   
4523   return NULL_SendMessageSequence
4524     (50, &CurrentBinRingtoneError, ringtone->length+3, 0x40, req);
4525 }
4526
4527 GSM_Error N6110_Reset(unsigned char type)
4528 {  
4529   return N6110_EnableExtendedCommands(type);
4530 }
4531
4532 void N6110_Dispatch0x01Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4533
4534   int tmp, count;
4535           
4536   switch (MessageBuffer[3]) {
4537
4538   /* Unknown message - it has been seen after the 0x07 message (call
4539      answered). Probably it has similar meaning. If you can solve
4540      this - just mail me. Pavel Janík ml.
4541
4542      The message looks like this:
4543
4544      Msg Destination: PC
4545      Msg Source: Phone
4546      Msg Type: 01
4547      Msg Unknown: 00
4548      Msg Len: 0e
4549
4550      Phone: [01 ][08 ][00 ] is the header of the frame
4551
4552      [03 ] is the call message subtype
4553
4554      [05 ] is the call sequence number
4555
4556      [05 ] unknown 
4557
4558      [00 ][01 ][03 ][02 ][91][00] are unknown but has been
4559      seen in the Incoming call message (just after the
4560      caller's name from the phonebook). But never change
4561      between phone calls :-(
4562   */
4563
4564   /* This may mean sequence number of 'just made' call - CK */
4565   case 0x02:
4566
4567 #ifdef DEBUG
4568     fprintf(stdout, _("Message: Call message, type 0x02:"));
4569     fprintf(stdout, _("   Exact meaning not known yet, sorry :-(\n"));
4570 #endif /* DEBUG */
4571
4572     break;
4573
4574   /* Possibly call OK */
4575   /* JD: I think that this means "call in progress" (incomming or outgoing) */
4576   case 0x03:
4577     
4578 #ifdef DEBUG
4579     fprintf(stdout, _("Message: Call message, type 0x03:"));
4580     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4581     fprintf(stdout, _("   Exact meaning not known yet, sorry :-(\n"));
4582 #endif /* DEBUG */
4583     
4584     CurrentCallSequenceNumber=MessageBuffer[4];
4585     CurrentIncomingCall[0]='D';
4586     if (CurrentCallPassup) CurrentCallPassup('D');
4587
4588     break;
4589
4590   /* Remote end has gone away before you answer the call.  Probably your
4591      mother-in-law or banker (which is worse?) ... */
4592   case 0x04:
4593
4594 #ifdef DEBUG
4595     fprintf(stdout, _("Message: Remote end hang up.\n"));
4596     fprintf(stdout, _("   Sequence nr. of the call: %d, error: %i"), MessageBuffer[4],MessageBuffer[6]);
4597
4598     switch (MessageBuffer[6]) {
4599       case 28: fprintf(stdout,_(" (info \"Invalid phone number\")"));break;
4600       case 34: fprintf(stdout,_(" (info \"Network busy\")"));break;
4601       case 42: fprintf(stdout,_(" (info \"Network busy\")"));break;
4602       case 47: fprintf(stdout,_(" (info \"Error in connection\")"));break;
4603       case 50: fprintf(stdout,_(" (info \"Check operator services\")"));break;       case 76: fprintf(stdout,_(" (info \"Check operator services\")"));break;
4604       case 111: fprintf(stdout,_(" (info \"Error in connection\")"));break;
4605     }
4606       
4607     fprintf(stdout,_("\n   For more details with errors see netmonitor manual (test 39) on www.marcin-wiacek.topnet.pl"));
4608     fprintf(stdout,_("\n   If know their meaning, GSM specs decribing them, contact with me on marcin-wiacek@topnet.pl. THX\n"));
4609 #endif /* DEBUG */
4610
4611     CurrentIncomingCall[0] = ' ';
4612     if (CurrentCallPassup) CurrentCallPassup(' ');
4613
4614     break;
4615
4616   /* Incoming call alert */
4617   case 0x05:
4618
4619 #ifdef DEBUG
4620     fprintf(stdout, _("Message: Incoming call alert:\n"));
4621
4622     /* We can have more then one call ringing - we can distinguish between
4623        them */
4624
4625     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4626     fprintf(stdout, _("   Number: "));
4627
4628     count=MessageBuffer[6];
4629
4630     for (tmp=0; tmp <count; tmp++)
4631       fprintf(stdout, "%c", MessageBuffer[7+tmp]);
4632
4633     fprintf(stdout, "\n");
4634
4635     fprintf(stdout, _("   Name: "));
4636
4637     for (tmp=0; tmp <MessageBuffer[7+count]; tmp++)
4638       fprintf(stdout, "%c", MessageBuffer[8+count+tmp]);
4639
4640     fprintf(stdout, "\n");
4641 #endif /* DEBUG */
4642
4643     count=MessageBuffer[6];
4644
4645     CurrentIncomingCall[0] = 0;
4646     for (tmp=0; tmp <count; tmp++)
4647       sprintf(CurrentIncomingCall, "%s%c", CurrentIncomingCall, MessageBuffer[7+tmp]);
4648
4649     break;
4650
4651   /* Call answered. Probably your girlfriend...*/
4652   case 0x07:
4653
4654 #ifdef DEBUG
4655     fprintf(stdout, _("Message: Call answered.\n"));
4656     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4657 #endif /* DEBUG */
4658
4659     break;
4660
4661   /* Call ended. Girlfriend is girlfriend, but time is money :-) */
4662   case 0x09:
4663
4664 #ifdef DEBUG
4665     fprintf(stdout, _("Message: Call ended by your phone.\n"));
4666     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4667 #endif /* DEBUG */
4668
4669     break;
4670
4671   /* This message has been seen with the message of subtype 0x09
4672      after I hang the call.
4673
4674   Msg Destination: PC
4675   Msg Source: Phone
4676   Msg Type: 01 
4677   Msg Unknown: 00
4678   Msg Len: 08
4679   Phone: [01 ][08 ][00 ][0a ][04 ][87 ][01 ][42B][1a ][c2 ]
4680
4681   What is the meaning of 87? Can you spell some magic light into
4682   this issue?
4683
4684   */
4685
4686   /* Probably means call over - CK */
4687   case 0x0a:
4688
4689 #ifdef DEBUG
4690     fprintf(stdout, _("Message: Call message, type 0x0a:"));
4691     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4692     fprintf(stdout, _("   Exact meaning not known yet, sorry :-(\n"));
4693 #endif /* DEBUG */
4694
4695     CurrentIncomingCall[0] = ' ';
4696     if (CurrentCallPassup) CurrentCallPassup(' ');
4697
4698     break;
4699
4700   case 0x40:
4701
4702 #ifdef DEBUG
4703       fprintf(stdout, _("Message: Answer for send DTMF or dial voice command\n"));
4704 #endif
4705
4706     if (CurrentSendDTMFError!=GE_NONE) CurrentSendDTMFError=GE_NONE;
4707
4708     if (CurrentDialVoiceError!=GE_NONE) CurrentDialVoiceError=GE_NONE;
4709
4710     break;
4711      
4712   default:
4713
4714 #ifdef DEBUG
4715     fprintf(stdout, _("Message: Unknown message of type 0x01\n"));
4716 #endif /* DEBUG */
4717     AppendLogText("Unknown msg\n",false);
4718
4719     break;      /* Visual C Don't like empty cases */
4720   }
4721 }
4722
4723 void N6110_Dispatch0x03Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4724
4725   int tmp, count;
4726     
4727   switch (MessageBuffer[3]) {
4728
4729   case 0x04:
4730
4731     /* AFAIK, this frame isn't used anywhere - it's rather for testing :-) */
4732     /* If you want see, if it works with your phone make something like that: */
4733
4734     /* unsigned char connect5[] = {N6110_FRAME_HEADER, 0x03}; */
4735     /* Protocol->SendMessage(4, 0x04, connect5); */
4736
4737     /*                                        Marcin-Wiacek@TopNet.PL */
4738     
4739 #ifdef WIN32
4740     sprintf(Current_IMEI, "%s", MessageBuffer+5);
4741     sprintf(Current_Model, "%s", MessageBuffer+21);
4742     sprintf(Current_Revision, "SW%s, HW%s", MessageBuffer+41, MessageBuffer+35);
4743 #else
4744     snprintf(Current_IMEI, GSM_MAX_IMEI_LENGTH, "%s", MessageBuffer+5);
4745     snprintf(Current_Model, GSM_MAX_MODEL_LENGTH, "%s", MessageBuffer+21);
4746     snprintf(Current_Revision, GSM_MAX_REVISION_LENGTH, "SW%s, HW%s", MessageBuffer+41, MessageBuffer+35);
4747 #endif
4748
4749 #ifdef DEBUG
4750     fprintf(stdout, _("Message: Mobile phone identification received:\n"));
4751     fprintf(stdout, _("   IMEI: %s\n"), Current_IMEI);
4752     fprintf(stdout, _("   Model: %s\n"), Current_Model);
4753     fprintf(stdout, _("   Production Code: %s\n"), MessageBuffer+27);
4754     fprintf(stdout, _("   HW: %s\n"), MessageBuffer+35);
4755     fprintf(stdout, _("   Firmware: %s\n"), MessageBuffer+41);
4756 #endif /* DEBUG */
4757
4758     break;
4759
4760   /* Get group data */    
4761   /* [ID],[name_len],[name].,[ringtone],[graphicon],[lenhi],[lenlo],[bitmap] */
4762   case 0x11:   
4763  
4764     if (CurrentGetBitmap!=NULL) {
4765       if (CurrentGetBitmap->number==MessageBuffer[4]) {
4766         count=MessageBuffer[5];
4767         memcpy(CurrentGetBitmap->text,MessageBuffer+6,count);
4768         CurrentGetBitmap->text[count]=0;
4769
4770 #ifdef DEBUG    
4771         fprintf(stdout, _("Message: Caller group datas\n"));
4772         fprintf(stdout, _("Caller group name: %s\n"),CurrentGetBitmap->text);
4773 #endif /* DEBUG */
4774
4775         count+=6;
4776
4777         CurrentGetBitmap->ringtone=MessageBuffer[count++];
4778 #ifdef DEBUG    
4779         fprintf(stdout, _("Caller group ringtone ID: %i"),CurrentGetBitmap->ringtone);
4780         if (CurrentGetBitmap->ringtone==16) fprintf(stdout,_(" (default)"));
4781         fprintf(stdout,_("\n"));
4782 #endif /* DEBUG */
4783
4784         CurrentGetBitmap->enabled=(MessageBuffer[count++]==1);
4785 #ifdef DEBUG    
4786         fprintf(stdout, _("Caller group logo "));
4787         if (CurrentGetBitmap->enabled)
4788           fprintf(stdout, _("enabled \n"));
4789         else
4790           fprintf(stdout, _("disabled \n"));
4791 #endif /* DEBUG */      
4792
4793         CurrentGetBitmap->size=MessageBuffer[count++]<<8;
4794         CurrentGetBitmap->size+=MessageBuffer[count++];
4795 #ifdef DEBUG    
4796         fprintf(stdout, _("Bitmap size=%i\n"),CurrentGetBitmap->size);
4797 #endif /* DEBUG */
4798
4799         count++;
4800         CurrentGetBitmap->width=MessageBuffer[count++];
4801         CurrentGetBitmap->height=MessageBuffer[count++];
4802         count++;
4803         tmp=GSM_GetBitmapSize(CurrentGetBitmap);
4804         if (CurrentGetBitmap->size>tmp) CurrentGetBitmap->size=tmp;
4805         memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count,CurrentGetBitmap->size);
4806         CurrentGetBitmapError=GE_NONE;
4807       } else {
4808 #ifdef DEBUG    
4809         fprintf(stdout, _("Message: Caller group datas received, but group number does not match (%i is not %i)\n"),MessageBuffer[4],CurrentGetBitmap->number);
4810 #endif
4811       }
4812     } else {
4813 #ifdef DEBUG
4814       fprintf(stdout, _("Message: Caller group data received but not requested!\n"));
4815 #endif
4816     }
4817     break;
4818
4819   /* Get group data error */
4820   case 0x12:   
4821       
4822     CurrentGetBitmapError=GE_UNKNOWN;   
4823 #ifdef DEBUG
4824     fprintf(stdout, _("Message: Error attempting to get caller group data.\n"));
4825 #endif   
4826     break;
4827
4828   /* Set group data OK */      
4829   case 0x14:   
4830       
4831     CurrentSetBitmapError=GE_NONE;      
4832 #ifdef DEBUG
4833     fprintf(stdout, _("Message: Caller group data set correctly.\n"));
4834 #endif
4835     break;
4836
4837   /* Set group data error */
4838   case 0x15:   
4839       
4840     CurrentSetBitmapError=GE_UNKNOWN;      
4841 #ifdef DEBUG
4842     fprintf(stdout, _("Message: Error attempting to set caller group data\n"));
4843 #endif
4844     break;  
4845   
4846   default:
4847
4848 #ifdef DEBUG
4849     fprintf(stdout, _("Message: Unknown message of type 0x03\n"));
4850 #endif /* DEBUG */
4851     AppendLogText("Unknown msg\n",false);
4852
4853     break;      /* Visual C Don't like empty cases */
4854   }
4855 }
4856
4857 void N6110_Dispatch0x05Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4858
4859   int tmp, count, length;
4860   bool issupported;
4861
4862 #ifdef DEBUG
4863   int i;
4864 #endif
4865
4866   switch (MessageBuffer[3]) {
4867
4868   /* Startup Logo */
4869   case 0x17:  
4870
4871 #ifdef DEBUG
4872     fprintf(stdout, _("Message: Startup Logo, welcome note and dealer welcome note received.\n"));
4873 #endif
4874
4875     if (CurrentGetBitmap!=NULL) {
4876        
4877       issupported=false;
4878        
4879       count=5;
4880        
4881       for (tmp=0;tmp<MessageBuffer[4];tmp++){
4882         switch (MessageBuffer[count++]) {
4883         case 0x01:
4884           if (CurrentGetBitmap->type==GSM_StartupLogo) {
4885             CurrentGetBitmap->height=MessageBuffer[count++];
4886             CurrentGetBitmap->width=MessageBuffer[count++];
4887             CurrentGetBitmap->size=GSM_GetBitmapSize(CurrentGetBitmap);
4888             length=CurrentGetBitmap->size;
4889             memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count,length);
4890           } else {
4891             //bitmap size
4892             length=MessageBuffer[count++];
4893             length=length*MessageBuffer[count++]/8;
4894           }
4895           count+=length;
4896 #ifdef DEBUG
4897           fprintf(stdout, _("Startup logo supported - "));
4898           if (length!=0) { fprintf(stdout, _("currently set\n"));   }
4899                     else { fprintf(stdout, _("currently empty\n")); }
4900 #endif
4901           if (CurrentGetBitmap->type==GSM_StartupLogo) issupported=true;
4902           break;
4903         case 0x02:
4904           length=MessageBuffer[count];
4905           if (CurrentGetBitmap->type==GSM_WelcomeNoteText) {
4906             memcpy(CurrentGetBitmap->text,MessageBuffer+count+1,length);
4907             CurrentGetBitmap->text[length]=0;
4908           }
4909 #ifdef DEBUG
4910           fprintf(stdout, _("Startup Text supported - "));
4911           if (length!=0)
4912           {
4913             fprintf(stdout, _("currently set to \""));
4914             for (i=0;i<length;i++) fprintf(stdout, _("%c"),MessageBuffer[count+1+i]);
4915             fprintf(stdout, _("\"\n"));
4916           } else {
4917             fprintf(stdout, _("currently empty\n"));
4918           }
4919 #endif
4920           count+=length+1;
4921           if (CurrentGetBitmap->type==GSM_WelcomeNoteText) issupported=true;
4922           break;
4923         case 0x03:
4924           length=MessageBuffer[count];
4925           if (CurrentGetBitmap->type==GSM_DealerNoteText) {
4926             memcpy(CurrentGetBitmap->text,MessageBuffer+count+1,length);
4927             CurrentGetBitmap->text[length]=0;
4928           }
4929 #ifdef DEBUG
4930           fprintf(stdout, _("Dealer Welcome supported - "));
4931           if (length!=0)
4932           {
4933             fprintf(stdout, _("currently set to \""));
4934             for (i=0;i<length;i++) fprintf(stdout, _("%c"),MessageBuffer[count+1+i]);
4935             fprintf(stdout, _("\"\n"));
4936           } else {
4937             fprintf(stdout, _("currently empty\n"));
4938           }
4939 #endif
4940           count+=length+1;
4941           if (CurrentGetBitmap->type==GSM_DealerNoteText) issupported=true;
4942           break;
4943         }
4944       }
4945       if (issupported) CurrentGetBitmapError=GE_NONE;
4946                   else CurrentGetBitmapError=GE_NOTSUPPORTED;
4947     } else {
4948 #ifdef DEBUG
4949       fprintf(stdout, _("Message: Startup logo received but not requested!\n"));
4950 #endif
4951     }
4952     break;
4953
4954   /* Set startup OK */
4955   case 0x19:   
4956     
4957     CurrentSetBitmapError=GE_NONE;    
4958 #ifdef DEBUG
4959     fprintf(stdout, _("Message: Startup logo, welcome note or dealer welcome note correctly set.\n"));
4960 #endif  
4961     break;      
4962
4963   /* Set Operator Logo OK */
4964   case 0x31:   
4965       
4966 #ifdef DEBUG
4967     fprintf(stdout, _("Message: Operator logo correctly set.\n"));
4968 #endif  
4969
4970     CurrentSetBitmapError=GE_NONE;      
4971     break;
4972
4973   /* Set Operator Logo Error */      
4974   case 0x32:  
4975       
4976 #ifdef DEBUG
4977     fprintf(stdout, _("Message: Error setting operator logo!\n"));
4978 #endif
4979
4980     CurrentSetBitmapError=GE_UNKNOWN;        
4981     break;
4982
4983   /* Operator Logo */
4984   /* [location],[netcode x 3],[lenhi],[lenlo],[bitmap] */ 
4985   case 0x34:
4986  
4987     if (CurrentGetBitmap!=NULL) {
4988
4989       count=5;  /* Location ignored. */
4990
4991       DecodeNetworkCode(MessageBuffer+count, CurrentGetBitmap->netcode);
4992       count=count+3;
4993
4994 #ifdef DEBUG
4995       fprintf(stdout, _("Message: Operator Logo for %s (%s) network received.\n"),
4996                            CurrentGetBitmap->netcode,
4997                            GSM_GetNetworkName(CurrentGetBitmap->netcode));
4998 #endif  
4999
5000       CurrentGetBitmap->size=MessageBuffer[count++]<<8;
5001       CurrentGetBitmap->size+=MessageBuffer[count++];
5002       count++;
5003       CurrentGetBitmap->width=MessageBuffer[count++];
5004       CurrentGetBitmap->height=MessageBuffer[count++];
5005       count++;
5006       tmp=GSM_GetBitmapSize(CurrentGetBitmap);
5007       if (CurrentGetBitmap->size>tmp) CurrentGetBitmap->size=tmp;
5008       memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count,CurrentGetBitmap->size);
5009       CurrentGetBitmapError=GE_NONE;
5010     } else {
5011 #ifdef DEBUG
5012       fprintf(stdout, _("Message: Operator logo received but not requested!\n"));
5013 #endif
5014     }
5015       
5016     break;
5017
5018   /* Get op logo error */      
5019   case 0x35:
5020      
5021 #ifdef DEBUG
5022     fprintf(stdout, _("Message: Error getting operator logo!\n"));
5023 #endif  
5024     CurrentGetBitmapError=GE_UNKNOWN; 
5025     break;
5026
5027   default:
5028
5029 #ifdef DEBUG
5030     fprintf(stdout, _("Message: Unknown message of type 0x05\n"));
5031 #endif /* DEBUG */
5032     AppendLogText("Unknown msg\n",false);
5033
5034     break;
5035   }
5036 }
5037
5038 void N6110_Dispatch0x06Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5039
5040   int tmp;
5041   unsigned char output[160];
5042
5043 #ifdef DEBUG
5044   int i;
5045 #endif
5046     
5047   switch (MessageBuffer[3]) {
5048
5049   case 0x05:
5050
5051     /* MessageBuffer[3] = 0x05
5052        MessageBuffer[4] = 0x00
5053        MessageBuffer[5] = 0x0f
5054        MessageBuffer[6] = 0x03
5055        MessageBuffer[7] = length of packed message
5056
5057        This is all I have seen - Gerry Anderson */
5058
5059     tmp=GSM_UnpackEightBitsToSeven(0, 82, 82, MessageBuffer+8, output);
5060
5061 #ifdef DEBUG
5062
5063     fprintf(stdout, _("Message from Network operator: "));
5064
5065     for (i=0; i<tmp; i++)
5066        fprintf(stdout, "%c", DecodeWithDefaultAlphabet(output[i]));
5067
5068     fprintf(stdout, "\n");
5069
5070 #endif /* DEBUG */
5071
5072     break;
5073
5074   default:
5075
5076 #ifdef DEBUG
5077     fprintf(stdout, _("Message: Unknown message of type 0x06\n"));
5078 #endif /* DEBUG */
5079     AppendLogText("Unknown msg\n",false);
5080
5081     break;
5082   }
5083 }
5084
5085 void N6110_Dispatch0x09Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5086     
5087   switch (MessageBuffer[3]) {
5088     
5089   case 0x80:    
5090 #ifdef DEBUG
5091     fprintf(stdout, _("Message: SIM card login\n"));
5092 #endif
5093     break;
5094
5095   case 0x81:    
5096 #ifdef DEBUG
5097     fprintf(stdout, _("Message: SIM card logout\n"));
5098 #endif
5099     break;
5100       
5101   default:
5102 #ifdef DEBUG
5103     fprintf(stdout, _("Unknown message of type 0x09.\n"));      
5104 #endif
5105     AppendLogText("Unknown msg\n",false);
5106     break;
5107   }
5108 }
5109
5110 void N6110_Dispatch0x13Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5111
5112   switch(MessageBuffer[3]) {
5113     
5114   case 0x6a:
5115
5116 #ifdef DEBUG
5117     fprintf(stdout, _("Message: Calendar Alarm active\n"));
5118     fprintf(stdout, _("   Item number: %d\n"), MessageBuffer[4]);
5119 #endif /* DEBUG */
5120
5121   default:
5122 #ifdef DEBUG
5123     fprintf(stdout, _("Unknown message of type 0x13.\n"));      
5124 #endif
5125     AppendLogText("Unknown msg\n",false);
5126     break;
5127   }
5128 }
5129
5130 void N6110_Dispatch0x40Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5131
5132   int i;
5133   
5134   switch(MessageBuffer[2]) {
5135
5136   case 0x02:
5137
5138 #ifdef DEBUG
5139     fprintf(stdout, _("Message: ACK for simlock opening part 1\n"));
5140 #endif /* DEBUG */
5141     
5142     CurrentMagicError=GE_NONE;
5143     break;
5144     
5145   case 0x7c:
5146
5147 #ifdef DEBUG
5148     fprintf(stdout, _("Message: Answer for call commands.\n"));
5149 #endif
5150     
5151     CurrentDialVoiceError=GE_NONE;      
5152     break;
5153       
5154   case 0x81:
5155
5156 #ifdef DEBUG
5157     fprintf(stdout, _("Message: ACK for simlock opening part 2\n"));
5158 #endif /* DEBUG */
5159     
5160     CurrentMagicError=GE_NONE;
5161     break;
5162
5163   case 0x82:
5164
5165 #ifdef DEBUG
5166       fprintf(stdout, _("Message: ACK for simlock closing\n"));
5167 #endif /* DEBUG */
5168     
5169     CurrentMagicError=GE_NONE;
5170     break;
5171
5172   case 0xd4:
5173
5174     switch (MessageBuffer[5]) {
5175       case 0xa0:
5176 #ifdef DEBUG
5177         fprintf(stdout,_("Message: EEPROM contest received\n"));
5178 #endif
5179
5180         if (MessageBuffer[8]!=0x00) {
5181           for (i=9;i<MessageLength;i++) {
5182             fprintf(stdout,_("%c"), MessageBuffer[i]);
5183         }
5184
5185         CurrentMagicError=GE_NONE;
5186       }
5187       
5188       break;
5189     }
5190       
5191 #ifdef DEBUG
5192     fprintf(stdout, _("Unknown message of type 0x40.\n"));
5193 #endif /* DEBUG */
5194     AppendLogText("Unknown msg\n",false);      
5195     break;
5196
5197   case 0xcf:
5198
5199     N6110_DisplayTestsInfo(MessageBuffer);
5200     break;
5201       
5202   default:
5203
5204 #ifdef DEBUG
5205     fprintf(stdout, _("Unknown message of type 0x40.\n"));
5206 #endif /* DEBUG */
5207     AppendLogText("Unknown msg\n",false);
5208     break;      /* Visual C Don't like empty cases */
5209   }
5210 }
5211
5212 void N6110_Dispatch0x47Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5213
5214   int count;
5215   
5216   switch(MessageBuffer[3]) {
5217     
5218   case 0x02:
5219
5220     count=5;
5221     
5222     if (MessageBuffer[5]!=0) {
5223       strcpy(CurrentGetBitmap->Sender,GSM_UnpackSemiOctetNumber(MessageBuffer+5,true));
5224
5225       while (MessageBuffer[count]!=0) {
5226         count++;
5227       }
5228
5229       count++;
5230     } else {
5231       strcpy(CurrentGetBitmap->Sender,"\0");
5232
5233       count+=3;
5234     }
5235
5236     memcpy(CurrentGetBitmap->text,MessageBuffer+count+1,MessageBuffer[count]);
5237     CurrentGetBitmap->text[MessageBuffer[count]]=0;
5238
5239     if (MessageBuffer[count]!=0)
5240       count+=MessageBuffer[count];
5241
5242     count++;
5243
5244 #ifdef DEBUG
5245     fprintf(stdout,_("Picture Image received, text \"%s\", sender %s\n"),CurrentGetBitmap->text,CurrentGetBitmap->Sender);
5246 #endif
5247
5248     CurrentGetBitmap->width=MessageBuffer[count+1];
5249     CurrentGetBitmap->height=MessageBuffer[count+2]; 
5250     CurrentGetBitmap->size=GSM_GetBitmapSize(CurrentGetBitmap);
5251       
5252     memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count+4,CurrentGetBitmap->size);
5253       
5254     CurrentGetBitmapError=GE_NONE;
5255     break;
5256
5257   case 0x04:
5258
5259 #ifdef DEBUG
5260     fprintf(stdout,_("Getting or setting Picture Image - OK\n"));
5261 #endif
5262     CurrentSetBitmapError=GE_NONE;
5263     CurrentGetBitmapError=GE_NONE;
5264     break;      
5265
5266   case 0x05:
5267
5268 #ifdef DEBUG
5269     fprintf(stdout,_("Setting Picture Image - invalid location or other error\n"));
5270 #endif
5271     CurrentSetBitmapError=GE_UNKNOWN;
5272     break;      
5273
5274   case 0x06:
5275
5276 #ifdef DEBUG
5277     fprintf(stdout,_("Getting Picture Image - invalid location or other error\n"));
5278 #endif
5279     CurrentGetBitmapError=GE_UNKNOWN;
5280     break;      
5281
5282   default:
5283
5284 #ifdef DEBUG
5285     fprintf(stdout, _("Unknown message of type 0x47.\n"));
5286 #endif /* DEBUG */
5287     AppendLogText("Unknown msg\n",false);
5288     break;      /* Visual C Don't like empty cases */
5289   }
5290 }
5291
5292 void N6110_DispatchACKMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5293   char buffer[50];
5294   
5295   sprintf(buffer,"Received ACK %02x %02x\n",MessageBuffer[0],MessageBuffer[1]);
5296   AppendLog(buffer,strlen(buffer),false);
5297
5298 #ifdef DEBUG
5299   fprintf(stdout, _("[Received Ack of type %02x, seq: %2x]\n"), MessageBuffer[0],
5300                                                                 MessageBuffer[1]);
5301 #endif /* DEBUG */
5302   
5303   CurrentLinkOK = true;
5304 }
5305
5306 void N6110_Dispatch0xD0Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5307    
5308 #ifdef DEBUG
5309   fprintf(stdout, _("Message: The phone is powered on - seq 1.\n"));
5310 #endif /* DEBUG */
5311
5312 }
5313
5314 /* This function is used for parsing the RLP frame into fields. */
5315 void N6110_RX_HandleRLPMessage(u8 *MessageBuffer)
5316 {
5317
5318   RLP_F96Frame frame;
5319   int count;
5320   int valid = true;
5321
5322   /* We do not need RLP frame parsing to be done when we do not have callback
5323      specified. */
5324   if (CurrentRLP_RXCallback == NULL)
5325     return;
5326     
5327   /* Anybody know the official meaning of the first two bytes?
5328      Nokia 6150 sends junk frames starting D9 01, and real frames starting
5329      D9 00. We'd drop the junk frames anyway because the FCS is bad, but
5330      it's tidier to do it here. We still need to call the callback function
5331      to give it a chance to handle timeouts and/or transmit a frame */
5332   if (MessageBuffer[0] == 0xd9 && MessageBuffer[1] == 0x01)
5333     valid = false;
5334
5335   /* Nokia uses 240 bit frame size of RLP frames as per GSM 04.22
5336      specification, so Header consists of 16 bits (2 bytes). See section 4.1
5337      of the specification. */
5338     
5339   frame.Header[0] = MessageBuffer[2];
5340   frame.Header[1] = MessageBuffer[3];
5341
5342   /* Next 200 bits (25 bytes) contain the Information. We store the
5343      information in the Data array. */
5344
5345   for (count = 0; count < 25; count ++)
5346     frame.Data[count] = MessageBuffer[4 + count];
5347
5348   /* The last 24 bits (3 bytes) contain FCS. */
5349
5350   frame.FCS[0] = MessageBuffer[29];
5351   frame.FCS[1] = MessageBuffer[30];
5352   frame.FCS[2] = MessageBuffer[31];
5353
5354   /* Here we pass the frame down in the input stream. */
5355   CurrentRLP_RXCallback(valid ? &frame : NULL);
5356 }
5357
5358 void N6110_Dispatch0xF4Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5359
5360 #ifdef DEBUG
5361   fprintf(stdout, _("Message: The phone is powered on - seq 2.\n"));
5362 #endif /* DEBUG */
5363
5364 }
5365
5366 void N6110_ReplyIncomingSMS(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5367
5368   GSM_SMSMessage NullSMS;
5369
5370   switch (MessageBuffer[6]) {
5371
5372     case 0x00: NullSMS.Type = GST_SMS; NullSMS.folder = GST_INBOX; break;
5373     case 0x01: NullSMS.Type = GST_DR;  NullSMS.folder = GST_INBOX; break;
5374
5375     /* Is it possible ? */
5376     case 0x02: NullSMS.Type = GST_SMS; NullSMS.folder = GST_OUTBOX; break;      
5377     default:   NullSMS.Type = GST_UN;                               break;
5378   }
5379
5380 #ifdef DEBUG
5381   if (NullSMS.Type == GST_DR)
5382     fprintf(stdout, _("Message: SMS Message (Report) Received\n"));
5383   else 
5384     fprintf(stdout, _("Message: SMS Message Received\n"));  
5385 #endif /* DEBUG */
5386
5387   GSM_DecodeNokiaSMSFrame(&NullSMS, MessageBuffer+7, MessageLength-7);
5388
5389 #ifdef DEBUG
5390   fprintf(stdout, _("\n"));      
5391 #endif /* DEBUG */
5392 }
5393
5394 void N6110_DispatchMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5395
5396   bool unknown=false;
5397
5398   /* Switch on the basis of the message type byte */
5399   switch (MessageType) {
5400           
5401   /* Call information */
5402   case 0x01:
5403
5404     N6110_Dispatch0x01Message(MessageLength, MessageBuffer, MessageType);
5405     break;
5406
5407   /* SMS handling */
5408   case 0x02:
5409     switch (MessageBuffer[3]) {
5410       case 0x02:
5411       case 0x03:N6110_ReplySendSMSMessage(MessageLength,MessageBuffer,MessageType);break;
5412       case 0x10:N6110_ReplyIncomingSMS(MessageLength,MessageBuffer,MessageType);break;
5413       case 0x21:N6110_ReplySetCellBroadcast(MessageLength, MessageBuffer, MessageType);break;
5414       case 0x23:N6110_ReplyReadCellBroadcast(MessageLength, MessageBuffer, MessageType);break;
5415       case 0x31:N6110_ReplySetSMSCenter(MessageLength,MessageBuffer,MessageType);break;
5416       case 0x34:
5417       case 0x35:N6110_ReplyGetSMSCenter(MessageLength,MessageBuffer,MessageType);break;
5418       default  :unknown=true;break;
5419     }
5420     break;
5421
5422   /* Phonebook handling */
5423   case 0x03:
5424     switch (MessageBuffer[3]) {
5425       case 0x02:
5426       case 0x03:N6110_ReplyGetMemoryLocation(MessageLength,MessageBuffer,MessageType);break;
5427       case 0x05:
5428       case 0x06:N6110_ReplyWritePhonebookLocation(MessageLength,MessageBuffer,MessageType);break;
5429       case 0x08:
5430       case 0x09:N6110_ReplyGetMemoryStatus(MessageLength,MessageBuffer,MessageType);break;
5431       case 0x17:
5432       case 0x18:N6110_ReplyGetSpeedDial(MessageLength,MessageBuffer,MessageType);break;
5433       case 0x1a:
5434       case 0x1b:N6110_ReplySetSpeedDial(MessageLength,MessageBuffer,MessageType);break;
5435       default  :N6110_Dispatch0x03Message(MessageLength,MessageBuffer,MessageType);break;
5436     }
5437     break;
5438
5439   /* Phone status */     
5440   case 0x04:
5441     switch (MessageBuffer[3]) {
5442       case 0x02:N6110_ReplyRFBatteryLevel(MessageLength,MessageBuffer,MessageType);break;
5443       default  :unknown=true;break;
5444     }
5445     break;
5446       
5447   /* Startup Logo, Operator Logo and Profiles. */
5448   case 0x05:
5449     switch (MessageBuffer[3]) {
5450       case 0x11:N6110_ReplySetProfile    (MessageLength,MessageBuffer,MessageType);break;
5451       case 0x14:N6110_ReplyGetProfile    (MessageLength,MessageBuffer,MessageType);break;
5452       case 0x1b:N6110_ReplyGetProfile    (MessageLength,MessageBuffer,MessageType);break;
5453       case 0x1d:N6110_ReplySetProfile    (MessageLength,MessageBuffer,MessageType);break;
5454       case 0x37:N6110_ReplySetRingtone   (MessageLength,MessageBuffer,MessageType);break;
5455       case 0x38:N6110_ReplySetRingtone   (MessageLength,MessageBuffer,MessageType);break;
5456       default  :N6110_Dispatch0x05Message(MessageLength,MessageBuffer,MessageType);break;
5457     }
5458     break;
5459
5460   /* Network Operator Message to handset -> Gerry Anderson & prepaid info */
5461   /* Call diverts */
5462   case 0x06:
5463     switch (MessageBuffer[3]) {
5464       case 0x02:
5465       case 0x03:N6110_ReplyCallDivert    (MessageLength,MessageBuffer,MessageType);break;
5466       default  :N6110_Dispatch0x06Message(MessageLength,MessageBuffer,MessageType);break;
5467     }
5468     break;
5469
5470   /* Security code requests */
5471   case 0x08:
5472     switch (MessageBuffer[3]) {
5473       case 0x08:N6110_ReplyGetSecurityCodeStatus(MessageLength,MessageBuffer,MessageType);break;
5474       case 0x0b:N6110_ReplyEnterSecurityCode    (MessageLength,MessageBuffer,MessageType);break;
5475       default  :N6110_ReplyEnterSecurityCode    (MessageLength,MessageBuffer,MessageType);break;
5476     }
5477     break;
5478
5479   /* SIM login */
5480   case 0x09:
5481
5482     N6110_Dispatch0x09Message(MessageLength, MessageBuffer, MessageType);
5483     break;
5484
5485   /* Network info */
5486   case 0x0a:
5487     switch (MessageBuffer[3]) {
5488       case 0x71:N6110_ReplyGetNetworkInfo(MessageLength,MessageBuffer,MessageType);break;
5489       default  :unknown=true;break;
5490     }
5491     break;
5492
5493   /* Simulating key pressing */
5494   case 0x0c:
5495     switch (MessageBuffer[3]) {
5496       case 0x43:N6110_ReplyPressKey(MessageLength,MessageBuffer,MessageType);break;
5497       default  :unknown=true;break;
5498     }
5499     break;
5500
5501   /* Display */
5502   case 0x0d:
5503     switch (MessageBuffer[3]) {
5504       case 0x50:N6110_ReplyDisplayOutput   (MessageLength,MessageBuffer,MessageType);break;
5505       case 0x52:N6110_ReplyGetDisplayStatus(MessageLength,MessageBuffer,MessageType);break;
5506       case 0x54:N6110_ReplyDisplayOutput   (MessageLength,MessageBuffer,MessageType);break;
5507       default  :unknown=true;break;
5508     }
5509     break;
5510
5511   /* Phone Clock and Alarm */
5512   case 0x11:
5513     switch (MessageBuffer[3]) {
5514       case 0x61:N6110_ReplySetDateTime(MessageLength,MessageBuffer,MessageType);break;
5515       case 0x63:N6110_ReplyGetDateTime(MessageLength,MessageBuffer,MessageType);break;
5516       case 0x6c:N6110_ReplySetAlarm   (MessageLength,MessageBuffer,MessageType);break;
5517       case 0x6e:N6110_ReplyGetAlarm   (MessageLength,MessageBuffer,MessageType);break;
5518       default  :unknown=true;break;
5519     }
5520     break;
5521
5522   /* Calendar notes handling */
5523   case 0x13:
5524     switch (MessageBuffer[3]) {
5525       case 0x65:N6110_ReplyWriteCalendarNote (MessageLength,MessageBuffer,MessageType);break;
5526       case 0x67:N6110_ReplyGetCalendarNote   (MessageLength,MessageBuffer,MessageType);break;
5527       case 0x69:N6110_ReplyDeleteCalendarNote(MessageLength,MessageBuffer,MessageType);break;
5528       default  :N6110_Dispatch0x13Message    (MessageLength,MessageBuffer,MessageType);break;
5529     }
5530     break;
5531
5532   /* SMS Messages */
5533   case 0x14:
5534     switch (MessageBuffer[3]) {
5535       case 0x05:
5536       case 0x06:N6110_ReplySaveSMSMessage  (MessageLength,MessageBuffer,MessageType);break;
5537       case 0x08:
5538       case 0x09:N6110_ReplyGetSMSMessage   (MessageLength,MessageBuffer,MessageType);break;
5539       case 0x0b:N6110_ReplyDeleteSMSMessage(MessageLength,MessageBuffer,MessageType);break;
5540       case 0x37:
5541       case 0x38:N6110_ReplyGetSMSStatus    (MessageLength,MessageBuffer,MessageType);break;
5542       default  :unknown=true;break;
5543     }
5544     break;
5545
5546   /* WAP */
5547   case 0x3f:
5548     switch (MessageBuffer[3]) {
5549       case 0x01:
5550       case 0x02:N7110_ReplyEnableWAPCommands(MessageLength,MessageBuffer,MessageType);break;
5551       case 0x07:
5552       case 0x08:N7110_ReplyGetWAPBookmark   (MessageLength,MessageBuffer,MessageType);break;
5553       case 0x0a:
5554       case 0x0b:N7110_ReplySetWAPBookmark   (MessageLength,MessageBuffer,MessageType);break;
5555       case 0x16:
5556       case 0x17:
5557       case 0x1c:N7110_ReplyGetWAPSettings   (MessageLength,MessageBuffer,MessageType);break;
5558       default  :unknown=true;break;
5559     }
5560     break;
5561
5562   /* Internal phone functions? */
5563   case 0x40:
5564     switch (MessageBuffer[2]) {
5565       case 0x64:N6110_ReplyEnableExtendedCommands  (MessageLength,MessageBuffer,MessageType);break;
5566       case 0x65:N6110_ReplyResetPhoneSettings      (MessageLength,MessageBuffer,MessageType);break;
5567       case 0x66:N6110_ReplyIMEI                    (MessageLength,MessageBuffer,MessageType);break;
5568       case 0x6a:N6110_ReplyGetProductProfileSetting(MessageLength,MessageBuffer,MessageType);break;
5569       case 0x6b:N6110_ReplySetProductProfileSetting(MessageLength,MessageBuffer,MessageType);break;
5570       case 0x6e:N6110_ReplyGetSecurityCode         (MessageLength,MessageBuffer,MessageType);break;
5571       case 0x7e:N6110_ReplyNetmonitor              (MessageLength,MessageBuffer,MessageType);break;
5572       case 0x8a:N6110_ReplySimlockInfo             (MessageLength,MessageBuffer,MessageType);break;
5573       case 0x8b:N6110_ReplySetOperatorName         (MessageLength,MessageBuffer,MessageType);break;
5574       case 0x8c:N6110_ReplyGetOperatorName         (MessageLength,MessageBuffer,MessageType);break;
5575       case 0x8f:N6110_ReplyPlayTone                (MessageLength,MessageBuffer,MessageType);break;
5576       case 0x9e:N6110_ReplyGetBinRingtone          (MessageLength,MessageBuffer,MessageType);break;
5577       case 0xa0:N6110_ReplySetBinRingtone          (MessageLength,MessageBuffer,MessageType);break;
5578       case 0xc8:N6110_ReplyHW                      (MessageLength,MessageBuffer,MessageType);break;
5579       default  :N6110_Dispatch0x40Message          (MessageLength,MessageBuffer,MessageType);break;
5580     }
5581     break;
5582
5583   /* Picture Images */
5584   case 0x47:
5585
5586     N6110_Dispatch0x47Message(MessageLength, MessageBuffer, MessageType);
5587     break;
5588
5589   /* Mobile phone identification */
5590   case 0x64:
5591
5592     N6110_ReplyGetAuthentication(MessageLength, MessageBuffer, MessageType);
5593     break;
5594
5595   /***** Acknowlegment of our frames. *****/
5596   case FBUS_FRTYPE_ACK:
5597
5598     N6110_DispatchACKMessage(MessageLength, MessageBuffer, MessageType);
5599     break;
5600
5601   /***** Power on message. *****/
5602   case 0xd0:
5603
5604     N6110_Dispatch0xD0Message(MessageLength, MessageBuffer, MessageType);
5605     break;
5606
5607   case 0xd2:
5608
5609     N6110_ReplyID(MessageLength, MessageBuffer, MessageType);
5610     break;
5611   
5612   /***** RLP frame received. *****/
5613   case 0xf1:
5614
5615     N6110_RX_HandleRLPMessage(MessageBuffer);
5616     break;
5617
5618   /***** Power on message. *****/
5619   case 0xf4:
5620
5621     N6110_Dispatch0xF4Message(MessageLength, MessageBuffer, MessageType);
5622     break;
5623
5624   /***** Unknown message *****/
5625   /* If you think that you know the exact meaning of other messages - please
5626      let us know. */
5627   default:
5628
5629 #ifdef DEBUG
5630     fprintf(stdout, _("Message: Unknown message type.\n"));
5631 #endif /* DEBUG */
5632     AppendLogText("Unknown msg type\n",false);
5633
5634     unknown=false;
5635     break;
5636
5637   }
5638
5639   if (unknown) {
5640 #ifdef DEBUG
5641     fprintf(stdout, _("Unknown message of type %02x.\n"),MessageType);
5642 #endif
5643     AppendLogText("Unknown msg\n",false);
5644   }
5645 }