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