\r\n -> \n
[gnokii.git] / common / newmodules / n6110.c
1 /*
2
3   G N O K I I
4
5   A Linux/Unix toolset and driver for Nokia mobile phones.
6
7   Released under the terms of the GNU GPL, see file COPYING for more details.
8
9   This file provides an API for accessing functions on the 6110 and similar
10   phones.
11
12 */
13
14 /* "Turn on" prototypes in n-6110.h */
15
16 #define __n_6110_c 
17
18 /* System header files */
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22
23 #ifdef WIN32
24   #include "misc_win32.h"
25 #endif
26  
27 /* Various header file */
28 #ifndef VC6
29   #include "config.h"
30 #endif
31
32 #include "gsm-api.h"
33 #include "gsm-coding.h"
34 #include "newmodules/n6110.h"
35 #include "newmodules/n7110.h"
36 #include "protocol/fbus.h"
37 #include "devices/device.h"
38 /* Global variables used by code in gsm-api.c to expose the functions
39    supported by this model of phone. */
40
41
42
43
44
45
46
47 /* Here we initialise model specific functions. */
48 GSM_Functions N6110_Functions = {
49   N6110_Initialise,
50   N6110_DispatchMessage,
51   NULL_Terminate,
52   NULL_KeepAlive,
53   N6110_GetMemoryLocation,
54   N6110_WritePhonebookLocation,
55   N6110_GetSpeedDial,
56   N6110_SetSpeedDial,
57   N6110_GetMemoryStatus,
58   N6110_GetSMSStatus,
59   N6110_GetSMSCenter,
60   N6110_SetSMSCenter,
61   N6110_GetSMSMessage,
62   N6110_DeleteSMSMessage,
63   N6110_SendSMSMessage,
64   N6110_SaveSMSMessage,
65   N6110_GetRFLevel,
66   N6110_GetBatteryLevel,
67   N6110_GetPowerSource,
68   N6110_GetDisplayStatus,
69   N6110_EnterSecurityCode,
70   N6110_GetSecurityCodeStatus,
71   N6110_GetSecurityCode,
72   N6110_GetIMEI,
73   N6110_GetRevision,
74   N6110_GetModel,
75   N6110_GetDateTime,
76   N6110_SetDateTime,
77   N6110_GetAlarm,
78   N6110_SetAlarm,
79   N6110_DialVoice,
80   N6110_DialData,
81   N6110_GetIncomingCallNr,
82   N6110_GetNetworkInfo,
83   N6110_GetCalendarNote,
84   N6110_WriteCalendarNote,
85   N6110_DeleteCalendarNote,
86   N6110_NetMonitor,
87   N6110_SendDTMF,
88   N6110_GetBitmap,
89   N6110_SetBitmap,
90   N6110_SetRingTone,
91   N6110_SetBinRingTone,
92   N6110_GetBinRingTone,
93   N6110_Reset,
94   N6110_GetProfile,
95   N6110_SetProfile,
96   N6110_SendRLPFrame,
97   N6110_CancelCall,
98   N6110_PressKey,
99   N6110_EnableDisplayOutput,
100   N6110_DisableDisplayOutput,
101   N6110_EnableCellBroadcast,
102   N6110_DisableCellBroadcast,
103   N6110_ReadCellBroadcast,
104   N6110_PlayTone,
105   N6110_GetProductProfileSetting,
106   N6110_SetProductProfileSetting,
107   N6110_GetOperatorName,
108   N6110_SetOperatorName,
109   N6110_GetVoiceMailbox,  N6110_Tests,
110   N6110_SimlockInfo,
111   UNIMPLEMENTED,                 //GetCalendarNotesInfo
112   N6110_GetSMSFolders,
113   N6110_ResetPhoneSettings,
114   N7110_GetWAPBookmark,
115   N7110_SetWAPBookmark,
116   N7110_GetWAPSettings,
117   N6110_CallDivert,
118   N6110_AnswerCall,
119   N6110_GetManufacturer
120 };
121
122 /* Mobile phone information */
123
124 GSM_Information N6110_Information = {
125   "3210|3310|3330|5110|5130|5190|6110|6130|6150|6190|8210|8850",
126      /* Supported models in FBUS */
127   "3210|3310|3330|5110|5130|5190|6110|6130|6150|6190|8210|8850",
128      /* Supported models in MBUS */
129   "6110|6130|6150|8210|8850",
130      /* Supported models in FBUS over infrared */
131   "",
132      /* Supported models in FBUS over DLR3 */
133   "",
134      /* AT commands */
135   "8210|8850",
136      /* infrared sockets */
137   "6110|6130|6150|8210|8850",
138      /* Supported models in FBUS over infrared with Tekram device */  
139   4,                     /* Max RF Level */
140   0,                     /* Min RF Level */
141   GRF_Arbitrary,         /* RF level units */
142   4,                     /* Max Battery Level */
143   0,                     /* Min Battery Level */
144   GBU_Arbitrary,         /* Battery level units */
145   GDT_DateTime,          /* Have date/time support */
146   GDT_TimeOnly,          /* Alarm supports time only */
147   1                      /* Only one alarm available */
148 };
149
150 const char *N6110_MemoryType_String [] = {
151   "",   /* 0x00 */
152   "MT", /* 0x01 */
153   "ME", /* 0x02 */
154   "SM", /* 0x03 */
155   "FD", /* 0x04 */
156   "ON", /* 0x05 */
157   "EN", /* 0x06 */
158   "DC", /* 0x07 */
159   "RC", /* 0x08 */
160   "MC", /* 0x09 */
161 };
162
163 /* Magic bytes from the phone. */
164 unsigned char MagicBytes[4] = { 0x00, 0x00, 0x00, 0x00 };
165
166 /* For DisplayOutput */
167 char               PhoneScreen[5+1][27+1];
168 int                OldX=1000,OldY=0,NewX=0,NewY=0;
169
170 void N6110_ReplyEnableExtendedCommands(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
171
172 #ifdef DEBUG
173   fprintf(stdout, _("Message: Answer for EnableExtendedSecurityCommands frame, meaning not known :-(\n"));
174 #endif /* DEBUG */
175
176   CurrentEnableExtendedCommandsError=GE_NONE;   
177 }
178
179 /* If you set make some things (for example,
180    change Security Code from phone's menu, disable and enable
181    phone), it won't answer for 0x40 frame - you won't be able
182    to play tones, get netmonitor, etc.
183
184    This function do thing called "Enabling extended security commands" -
185    it enables 0x40 frame functions.
186
187    This frame can also some other things - see below */
188 GSM_Error N6110_EnableExtendedCommands (unsigned char status)
189 {
190   unsigned char req[4] = { 0x00,
191                            0x01,0x64, /* Enable extended commands request */
192                            0x01 };    /* 0x01 - on, 0x00 - off,
193                                          0x03 & 0x04 - soft & hard reset,
194                                          0x06 - CONTACT SERVICE */
195
196   /* 0x06 MAKES CONTACT SERVICE! BE CAREFULL! */
197   /* When use 0x03 and had during session changed time & date
198      some phones (like 6150 or 6210) can ask for time & date after reset
199      or disable clock on the screen */
200   if (status!=0x06) req[3] = status;
201
202   return NULL_SendMessageSequence
203     (50, &CurrentEnableExtendedCommandsError, 4, 0x40, req);
204 }
205
206 void N6110_ReplyIMEI(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
207
208 #if defined WIN32 || !defined HAVE_SNPRINTF
209   sprintf(Current_IMEI, "%s", MessageBuffer+4);
210 #else
211   snprintf(Current_IMEI, GSM_MAX_IMEI_LENGTH, "%s", MessageBuffer+4);
212 #endif
213
214 #ifdef DEBUG
215   fprintf(stdout, _("Message: IMEI %s received\n"),Current_IMEI);
216 #endif
217
218   CurrentGetIMEIError=GE_NONE;       
219 }
220
221 GSM_Error N6110_SendIMEIFrame()
222 {
223   unsigned char req[4] = {0x00, 0x01, 0x66, 0x00};  
224
225   GSM_Error error;
226
227   error=N6110_EnableExtendedCommands(0x01);
228   if (error!=GE_NONE) return error;
229   
230   return NULL_SendMessageSequence (20, &CurrentGetIMEIError, 4, 0x40, req);
231 }
232
233 void N6110_ReplyHW(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
234
235   int i, j;
236     
237   if (MessageBuffer[3]==0x05) {
238
239 #ifdef DEBUG
240     fprintf(stdout,_("Message: Hardware version received: "));
241 #endif
242
243     j=strlen(Current_Revision);
244     Current_Revision[j++]=',';
245     Current_Revision[j++]=' ';
246     Current_Revision[j++]='H';
247     Current_Revision[j++]='W';
248             
249     for (i=5;i<9;i++) {
250 #ifdef DEBUG
251       fprintf(stdout,_("%c"), MessageBuffer[i]);
252 #endif
253       Current_Revision[j++]=MessageBuffer[i];
254     }
255
256 #ifdef DEBUG
257     fprintf(stdout,_("\n"));
258 #endif
259
260     CurrentGetHWError=GE_NONE;
261   }
262 }
263
264 GSM_Error N6110_SendHWFrame()
265 {
266   unsigned char req[4] = {0x00, 0x01, 0xc8, 0x05};  
267
268   GSM_Error error;
269
270   error=N6110_EnableExtendedCommands(0x01);
271   if (error!=GE_NONE) return error;
272   
273   return NULL_SendMessageSequence (20, &CurrentGetHWError, 4, 0x40, req);
274 }
275
276 void N6110_ReplyID(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
277
278   int i, j;
279  
280 #ifdef DEBUG
281   fprintf(stdout, _("Message: Mobile phone model identification received:\n"));
282   fprintf(stdout, _("   Firmware: "));
283 #endif
284
285   strcpy(Current_Revision,"SW");
286     
287   i=6;j=2;
288   while (MessageBuffer[i]!=0x0a) {
289     Current_Revision[j]=MessageBuffer[i];
290 #ifdef DEBUG
291     fprintf(stdout, _("%c"),MessageBuffer[i]);
292 #endif
293     if (j==GSM_MAX_REVISION_LENGTH-1) {
294 #ifdef DEBUG
295       fprintf(stderr,_("ERROR: increase GSM_MAX_REVISION_LENGTH!\n"));
296 #endif  
297       break;
298     }
299     j++;
300     i++;
301   }
302   Current_Revision[j+1]=0;
303
304 #ifdef DEBUG
305   fprintf(stdout, _("\n   Firmware date: "));
306 #endif
307
308   i++;
309   while (MessageBuffer[i]!=0x0a) {
310 #ifdef DEBUG
311     fprintf(stdout, _("%c"),MessageBuffer[i]);
312 #endif
313     i++;
314   }
315
316 #ifdef DEBUG
317   fprintf(stdout, _("\n   Model: "));
318 #endif /* DEBUG */
319
320   i++;j=0;
321   while (MessageBuffer[i]!=0x0a) {
322     Current_Model[j]=MessageBuffer[i];
323 #ifdef DEBUG
324     fprintf(stdout, _("%c"),MessageBuffer[i]);
325 #endif
326     if (j==GSM_MAX_MODEL_LENGTH-1) {
327 #ifdef DEBUG
328       fprintf(stderr,_("ERROR: increase GSM_MAX_MODEL_LENGTH!\n"));
329 #endif  
330       break;
331     }
332     j++;
333     i++;
334   }
335   Current_Model[j+1]=0;
336
337 #ifdef DEBUG
338   fprintf(stdout, _("\n"));
339 #endif /* DEBUG */
340     
341   CurrentMagicError=GE_NONE;
342 }
343
344 GSM_Error N6110_SendIDFrame()
345 {
346   unsigned char req[5] = {N6110_FRAME_HEADER, 0x03, 0x00};  
347
348   return NULL_SendMessageSequence (50, &CurrentMagicError, 5, 0xd1, req);
349 }
350
351 /* This function send the status request to the phone. */
352 /* Seems to be ignored in N3210 */
353 GSM_Error N6110_SendStatusRequest(void)
354 {
355   unsigned char req[] = {N6110_FRAME_HEADER, 0x01};
356
357   Protocol->SendMessage(4, 0x04, req);
358
359   return (GE_NONE);
360 }
361
362 void N6110_ReplyGetAuthentication(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
363
364 #if defined WIN32 || !defined HAVE_SNPRINTF
365   sprintf(Current_IMEI, "%s", MessageBuffer+9);
366   sprintf(Current_Model, "%s", MessageBuffer+25);
367   sprintf(Current_Revision, "SW%s, HW%s", MessageBuffer+44, MessageBuffer+39);
368 #else
369   snprintf(Current_IMEI, GSM_MAX_IMEI_LENGTH, "%s", MessageBuffer+9);
370   snprintf(Current_Model, GSM_MAX_MODEL_LENGTH, "%s", MessageBuffer+25);
371   snprintf(Current_Revision, GSM_MAX_REVISION_LENGTH, "SW%s, HW%s", MessageBuffer+44, MessageBuffer+39);
372 #endif
373
374 #ifdef DEBUG
375   fprintf(stdout, _("Message: Mobile phone identification received:\n"));
376   fprintf(stdout, _("   IMEI: %s\n"), Current_IMEI);
377   fprintf(stdout, _("   Model: %s\n"), Current_Model);
378   fprintf(stdout, _("   Production Code: %s\n"), MessageBuffer+31);
379   fprintf(stdout, _("   HW: %s\n"), MessageBuffer+39);
380   fprintf(stdout, _("   Firmware: %s\n"), MessageBuffer+44);
381
382   /* These bytes are probably the source of the "Accessory not connected"
383      messages on the phone when trying to emulate NCDS... I hope....
384      UPDATE: of course, now we have the authentication algorithm. */
385   fprintf(stdout, _("   Magic bytes: %02x %02x %02x %02x\n"), MessageBuffer[50], MessageBuffer[51], MessageBuffer[52], MessageBuffer[53]);
386 #endif /* DEBUG */
387
388   MagicBytes[0]=MessageBuffer[50];
389   MagicBytes[1]=MessageBuffer[51];
390   MagicBytes[2]=MessageBuffer[52];
391   MagicBytes[3]=MessageBuffer[53];
392
393   CurrentMagicError=GE_NONE;
394 }
395
396 /* This function provides Nokia authentication protocol.
397
398    This code is written specially for gnokii project by Odinokov Serge.
399    If you have some special requests for Serge just write him to
400    apskaita@post.omnitel.net or serge@takas.lt
401
402    Reimplemented in C by Pavel Janík ml.
403
404    Nokia authentication protocol is used in the communication between Nokia
405    mobile phones (e.g. Nokia 6110) and Nokia Cellular Data Suite software,
406    commercially sold by Nokia Corp.
407
408    The authentication scheme is based on the token send by the phone to the
409    software. The software does it's magic (see the function
410    FB61_GetNokiaAuth()) and returns the result back to the phone. If the
411    result is correct the phone responds with the message "Accessory
412    connected!" displayed on the LCD. Otherwise it will display "Accessory not
413    supported" and some functions will not be available for use.
414
415    The specification of the protocol is not publicly available, no comment. */
416 void N6110_GetNokiaAuth(unsigned char *Imei, unsigned char *MagicBytes, unsigned char *MagicResponse)
417 {
418
419   int i, j, CRC=0;
420
421   /* This is our temporary working area. */
422
423   unsigned char Temp[16];
424
425   /* Here we put FAC (Final Assembly Code) and serial number into our area. */
426
427   Temp[0]  = Imei[6];
428   Temp[1]  = Imei[7];
429   Temp[2]  = Imei[8];
430   Temp[3]  = Imei[9];
431   Temp[4]  = Imei[10];
432   Temp[5]  = Imei[11];
433   Temp[6]  = Imei[12];
434   Temp[7]  = Imei[13];
435
436   /* And now the TAC (Type Approval Code). */
437
438   Temp[8]  = Imei[2];
439   Temp[9]  = Imei[3];
440   Temp[10] = Imei[4];
441   Temp[11] = Imei[5];
442
443   /* And now we pack magic bytes from the phone. */
444
445   Temp[12] = MagicBytes[0];
446   Temp[13] = MagicBytes[1];
447   Temp[14] = MagicBytes[2];
448   Temp[15] = MagicBytes[3];
449
450   for (i=0; i<=11; i++)
451     if (Temp[i + 1]& 1)
452       Temp[i]<<=1;
453
454   switch (Temp[15] & 0x03) {
455
456   case 1:
457   case 2:
458     j = Temp[13] & 0x07;
459
460     for (i=0; i<=3; i++)
461       Temp[i+j] ^= Temp[i+12];
462
463     break;
464
465   default:
466     j = Temp[14] & 0x07;
467
468     for (i=0; i<=3; i++)
469       Temp[i + j] |= Temp[i + 12];
470   }
471
472   for (i=0; i<=15; i++)
473     CRC ^= Temp[i];
474
475   for (i=0; i<=15; i++) {
476
477     switch (Temp[15 - i] & 0x06) {
478
479     case 0:
480       j = Temp[i] | CRC;
481       break;
482
483     case 2:
484     case 4:
485       j = Temp[i] ^ CRC;
486       break;
487
488     case 6:
489       j = Temp[i] & CRC;
490       break;
491     }
492   
493     if (j == CRC)
494       j = 0x2c;
495
496     if (Temp[i] == 0)
497       j = 0;
498
499     MagicResponse[i] = j;
500
501   }
502 }
503
504 GSM_Error N6110_Authentication()
505 {
506   unsigned char connect1[] = {N6110_FRAME_HEADER, 0x0d, 0x00, 0x00, 0x02};
507   unsigned char connect2[] = {N6110_FRAME_HEADER, 0x20, 0x02};
508   unsigned char connect3[] = {N6110_FRAME_HEADER, 0x0d, 0x01, 0x00, 0x02};
509   unsigned char connect4[] = {N6110_FRAME_HEADER, 0x10};
510   
511   unsigned char magic_connect[] = {N6110_FRAME_HEADER,
512   0x12,
513
514   /* The real magic goes here ... These bytes are filled in with the
515      function N6110_GetNokiaAuth(). */
516
517   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
519
520   /* NOKIA&GNOKII Accessory */
521
522   0x4e, 0x4f, 0x4b, 0x49, 0x41, 0x26, 0x4e, 0x4f, 0x4b, 0x49, 0x41, 0x20,
523   0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x79,
524   
525   0x00, 0x00, 0x00, 0x00};
526
527 #ifdef DEBUG
528   fprintf(stdout,_("Making authentication!\n"));
529 #endif
530
531   usleep(100); Protocol->SendMessage(7, 0x02, connect1);
532   usleep(100); Protocol->SendMessage(5, 0x02, connect2);
533   usleep(100); Protocol->SendMessage(7, 0x02, connect3);
534       
535   CurrentMagicError = GE_BUSY;
536
537   usleep(100); Protocol->SendMessage(4, 0x64, connect4);
538   if (NULL_WaitUntil(50,&CurrentMagicError)!=GE_NONE) return GE_TIMEOUT;
539
540   N6110_GetNokiaAuth(Current_IMEI, MagicBytes, magic_connect+4);
541
542   Protocol->SendMessage(45, 0x64, magic_connect);
543
544 #ifdef DEBUG
545   fprintf(stdout,_("End of authentication!\n"));
546 #endif
547
548   return GE_NONE;
549 }
550
551 /* Initialise variables and state machine. */
552 GSM_Error N6110_Initialise(char *port_device, char *initlength,
553                           GSM_ConnectionType connection,
554                           void (*rlp_callback)(RLP_F96Frame *frame))
555 {
556   unsigned char init_char = N6110_SYNC_BYTE;
557   unsigned char end_init_char = N6110_IR_END_SYNC_BYTE;
558
559   int count;
560   int InitLength;
561   
562   if (Protocol->Initialise(port_device,initlength,connection,rlp_callback)!=GE_NONE)
563   {
564     return GE_NOTSUPPORTED;
565   }
566
567   switch (CurrentConnectionType) {
568     case GCT_Irda:
569     case GCT_MBUS:
570       /* We don't think about authentication in Irda, because
571          AFAIK there are no phones working over sockets
572          and having authentication. In MBUS it doesn't work */
573       usleep(100);
574
575       if (N6110_SendIDFrame()!=GE_NONE) return GE_TIMEOUT;
576     
577       if (N6110_SendIMEIFrame()!=GE_NONE) return GE_TIMEOUT;    
578
579       if (N6110_SendHWFrame()!=GE_NONE) return GE_TIMEOUT;    
580
581       CurrentLinkOK = true;                                 
582       break;
583       
584     case GCT_FBUS:
585     case GCT_Infrared:
586     case GCT_Tekram:
587       InitLength = atoi(initlength);
588
589       if ((strcmp(initlength, "default") == 0) || (InitLength == 0)) {
590         InitLength = 250;       /* This is the usual value, lower may work. */
591       }
592
593       if (CurrentConnectionType==GCT_Infrared ||
594           CurrentConnectionType==GCT_Tekram) {
595 #ifdef DEBUG
596         fprintf(stdout,_("Setting infrared for FBUS communication...\n"));
597 #endif
598         device_changespeed(9600);
599       }
600
601 #ifdef DEBUG
602       fprintf(stdout,_("Writing init chars...."));
603 #endif
604
605       /* Initialise link with phone or what have you */
606       /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
607          empirical. */
608       for (count = 0; count < InitLength; count ++) {
609         if (CurrentConnectionType!=GCT_Infrared &&
610             CurrentConnectionType!=GCT_Tekram)         usleep(100);
611         Protocol->WritePhone(1,&init_char);
612       }
613
614       if (CurrentConnectionType==GCT_Infrared ||
615           CurrentConnectionType==GCT_Tekram)      {
616         Protocol->WritePhone(1,&end_init_char);
617         usleep(200000);
618       }
619
620 #ifdef DEBUG
621       fprintf(stdout,_("Done\n"));  
622 #endif
623
624       if (CurrentConnectionType==GCT_Infrared ||
625           CurrentConnectionType==GCT_Tekram)      {
626         device_changespeed(115200);    
627       }
628
629       N6110_SendStatusRequest();
630     
631       usleep(100);
632
633       if (N6110_SendIDFrame()!=GE_NONE) return GE_TIMEOUT;
634     
635       /* N51xx/61xx have something called authentication.
636          After making it phone display "Accessory connected"
637          and probably give access to some function (I'm not too sure about it !)
638          Anyway, I make it now for N51xx/61xx */
639       if (GetModelFeature (FN_AUTHENTICATION)!=0) {
640         if (N6110_Authentication()!=GE_NONE) return GE_TIMEOUT;
641       } else {        /* No authentication */
642         if (N6110_SendIMEIFrame()!=GE_NONE) return GE_TIMEOUT;    
643
644         if (N6110_SendHWFrame()!=GE_NONE) return GE_TIMEOUT;    
645       }
646       
647       break;
648     default:
649 #ifdef DEBUG
650       fprintf(stdout,_("Unknown connection type in n6110.c!\n"));
651 #endif
652       break;
653   }
654
655   return (GE_NONE);
656 }
657
658 /* This function translates GMT_MemoryType to N6110_MEMORY_xx */
659 int N6110_GetMemoryType(GSM_MemoryType memory_type)
660 {
661
662   int result;
663
664   switch (memory_type) {
665
666      case GMT_MT: result = N6110_MEMORY_MT; break;
667      case GMT_ME: result = N6110_MEMORY_ME; break;
668      case GMT_SM: result = N6110_MEMORY_SM; break;
669      case GMT_FD: result = N6110_MEMORY_FD; break;
670      case GMT_ON: result = N6110_MEMORY_ON; break;
671      case GMT_EN: result = N6110_MEMORY_EN; break;
672      case GMT_DC: result = N6110_MEMORY_DC; break;
673      case GMT_RC: result = N6110_MEMORY_RC; break;
674      case GMT_MC: result = N6110_MEMORY_MC; break;
675      default    : result = N6110_MEMORY_XX;
676
677    }
678
679    return (result);
680 }
681
682 void N6110_ReplyCallDivert(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
683
684   switch (MessageBuffer[3]) {
685
686   case 0x02:
687
688 #ifdef DEBUG
689     fprintf(stdout, _("Message: Call divert status received\n"));
690     fprintf(stdout, _("   Divert type: "));
691     switch (MessageBuffer[6]) {
692       case 0x43: fprintf(stdout, _("when busy"));break;
693       case 0x3d: fprintf(stdout, _("when not answered"));break;
694       case 0x3e: fprintf(stdout, _("when phone off or no coverage"));break;
695       case 0x15: fprintf(stdout, _("all types of diverts"));break; //?
696       case 0x02: fprintf(stdout, _("all types of diverts"));break; //?
697       default:   fprintf(stdout, _("unknown %i"),MessageBuffer[6]);break;
698     }
699     fprintf(stdout, _("\n   Calls type : "));
700     if (MessageBuffer[6]==0x02)
701       fprintf(stdout, _("voice, fax & data")); //?
702     else {
703       switch (MessageBuffer[8]) {
704         case 0x0b: fprintf(stdout, _("voice"));break;
705         case 0x0d: fprintf(stdout, _("fax"));break;
706         case 0x19: fprintf(stdout, _("data"));break;
707         default:   fprintf(stdout, _("unknown %i"),MessageBuffer[8]);break;
708       }
709     }
710     fprintf(stdout, _("\n"));     
711     if (MessageBuffer[10]==0x01) {
712       fprintf(stdout, _("   Status     : active\n"));
713       fprintf(stdout, _("   Timeout    : %i seconds\n"),MessageBuffer[45]);
714       fprintf(stdout, _("   Number     : %s\n"),GSM_UnpackSemiOctetNumber(MessageBuffer+12,true));
715     } else {
716       fprintf(stdout, _("   Status     : deactivated\n"));     
717     }
718 #endif /* DEBUG */
719  
720     switch (MessageBuffer[6]) {
721       case 0x43: CurrentCallDivert->DType=GSM_CDV_Busy;break;
722       case 0x3d: CurrentCallDivert->DType=GSM_CDV_NoAnswer;break;
723       case 0x3e: CurrentCallDivert->DType=GSM_CDV_OutOfReach;break;
724       case 0x15: CurrentCallDivert->DType=GSM_CDV_AllTypes;break; //?
725       case 0x02: CurrentCallDivert->DType=GSM_CDV_AllTypes;break; //?
726     }
727
728     if (MessageBuffer[6]==0x02) //?
729       CurrentCallDivert->CType=GSM_CDV_AllCalls;
730     else {
731       switch (MessageBuffer[8]) {
732         case 0x0b: CurrentCallDivert->CType=GSM_CDV_VoiceCalls;break;
733         case 0x0d: CurrentCallDivert->CType=GSM_CDV_FaxCalls;  break;
734         case 0x19: CurrentCallDivert->CType=GSM_CDV_DataCalls; break;
735       }
736     }
737
738     if (MessageBuffer[10]==0x01) {
739       CurrentCallDivert->Enabled=true;
740       CurrentCallDivert->Timeout=MessageBuffer[45];
741       strcpy(CurrentCallDivert->Number,GSM_UnpackSemiOctetNumber(MessageBuffer+12,true));
742     } else {
743       CurrentCallDivert->Enabled=false;
744     }
745
746     CurrentCallDivertError=GE_NONE;
747     break;
748
749   case 0x03:
750 #ifdef DEBUG
751     fprintf(stdout, _("Message: Call divert status receiving error ?\n"));
752 #endif
753     CurrentCallDivertError=GE_UNKNOWN;
754     break;
755   }
756 }
757
758 GSM_Error N6110_CallDivert(GSM_CallDivert *cd)
759 {
760   char req[55] = { N6110_FRAME_HEADER, 0x01,
761                                        0x00, /* operation */
762                                        0x00,
763                                        0x00, /* divert type */
764                                        0x00, /* call type */
765                                        0x00 };
766   GSM_Error error;
767
768   int length = 0x09;
769
770   switch (cd->Operation) {
771     case GSM_CDV_Register:
772     case GSM_CDV_Enable:
773       req[4] = 0x03;
774       req[8] = 0x01;
775       req[29]= GSM_PackSemiOctetNumber(cd->Number, req + 9, false);
776       req[52]= cd->Timeout;
777       length = 55;
778       break;
779     case GSM_CDV_Erasure:
780     case GSM_CDV_Disable:
781       req[4] = 0x04;
782       break;
783     case GSM_CDV_Query:
784       req[4] = 0x05;
785       break;
786     default:
787       return GE_NOTIMPLEMENTED;
788   }
789
790   switch (cd->DType) {
791     case GSM_CDV_AllTypes  : req[6] = 0x15; break;
792     case GSM_CDV_Busy      : req[6] = 0x43; break;
793     case GSM_CDV_NoAnswer  : req[6] = 0x3d; break;
794     case GSM_CDV_OutOfReach: req[6] = 0x3e; break;
795     default:                 return GE_NOTIMPLEMENTED;
796   }
797
798   if ((cd->DType == GSM_CDV_AllTypes) &&
799       (cd->CType == GSM_CDV_AllCalls))
800     req[6] = 0x02;
801
802   switch (cd->CType) {
803     case GSM_CDV_AllCalls  :                break;
804     case GSM_CDV_VoiceCalls: req[7] = 0x0b; break;
805     case GSM_CDV_FaxCalls  : req[7] = 0x0d; break;
806     case GSM_CDV_DataCalls : req[7] = 0x19; break;
807     default:                 return GE_NOTIMPLEMENTED;
808   }
809
810   CurrentCallDivert = cd;
811
812   error=NULL_SendMessageSequence
813     (100, &CurrentCallDivertError, length, 0x06, req);
814
815   CurrentCallDivert = NULL;
816
817   return error;
818 }
819
820 GSM_Error N6110_Tests()
821 {
822   unsigned char buffer[3]={0x00,0x01,0xcf};
823   unsigned char buffer3[8]={0x00,0x01,0xce,0x1d,0xfe,0x23,0x00,0x00};
824   
825   GSM_Error error;
826
827   error=N6110_EnableExtendedCommands(0x01);
828   if (error!=GE_NONE) return error;
829
830   //make almost all tests
831   Protocol->SendMessage(8, 0x40, buffer3);
832
833   while (GSM->Initialise(PortDevice, "50", CurrentConnectionType, CurrentRLP_RXCallback)!=GE_NONE) {};
834
835   sleep(2);
836
837   return NULL_SendMessageSequence
838     (200, &CurrentNetworkInfoError, 3, 0x40, buffer);  
839 }
840
841 void N6110_DisplayTestsInfo(u8 *MessageBuffer) {
842
843   int i;
844
845   CurrentNetworkInfoError=GE_NONE;
846
847   for (i=0;i<MessageBuffer[3];i++) {
848     switch (i) {
849       case 0: fprintf(stdout,_("Unknown(%i)              "),i);break;
850       case 1: fprintf(stdout,_("MCU ROM checksum        "));break;
851       case 2: fprintf(stdout,_("MCU RAM interface       "));break;
852       case 3: fprintf(stdout,_("MCU RAM component       "));break;
853       case 4: fprintf(stdout,_("MCU EEPROM interface    "));break;
854       case 5: fprintf(stdout,_("MCU EEPROM component    "));break;
855       case 6: fprintf(stdout,_("Real Time Clock battery "));break;
856       case 7: fprintf(stdout,_("CCONT interface         "));break;
857       case 8: fprintf(stdout,_("AD converter            "));break;
858       case 9: fprintf(stdout,_("SW Reset                "));break;
859       case 10:fprintf(stdout,_("Power Off               "));break;
860       case 11:fprintf(stdout,_("Security Data           "));break;
861       case 12:fprintf(stdout,_("EEPROM Tune checksum    "));break;
862       case 13:fprintf(stdout,_("PPM checksum            "));break;
863       case 14:fprintf(stdout,_("MCU download DSP        "));break;
864       case 15:fprintf(stdout,_("DSP alive               "));break;
865       case 16:fprintf(stdout,_("COBBA serial            "));break;
866       case 17:fprintf(stdout,_("COBBA paraller          "));break;
867       case 18:fprintf(stdout,_("EEPROM security checksum"));break;
868       case 19:fprintf(stdout,_("PPM validity            "));break;
869       case 20:fprintf(stdout,_("Warranty state          "));break;
870       case 21:fprintf(stdout,_("Simlock check           "));break;
871       case 22:fprintf(stdout,_("IMEI check?             "));break;//from PC-Locals.is OK?
872       default:fprintf(stdout,_("Unknown(%i)             "),i);break;
873     }
874     switch (MessageBuffer[4+i]) {
875       case 0:   fprintf(stdout,_(" : done, result OK"));break;
876       case 0xff:fprintf(stdout,_(" : not done, result unknown"));break;
877       case 254: fprintf(stdout,_(" : done, result NOT OK"));break;
878       default:  fprintf(stdout,_(" : result unknown(%i)"),MessageBuffer[4+i]);break;
879     }
880     fprintf(stdout,_("\n"));
881   }
882 }
883
884 void N6110_ReplySimlockInfo(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
885
886   int i, j;
887   
888   char uni[100];
889     
890 #ifdef DEBUG
891   fprintf(stdout, _("Message: Simlock info received\n"));
892
893   j=0;
894   for (i=0; i < 12; i++)
895   {
896     if (j<24) {
897       fprintf(stdout,_("%c"), ('0' + (MessageBuffer[9+i] >> 4)));
898       j++;
899     }
900     if (j==5 || j==15) fprintf(stdout, _("\n"));
901     if (j!=15) {
902       if (j<24) {
903         fprintf(stdout,_("%c"), ('0' + (MessageBuffer[9+i] & 0x0f)));
904         j++;
905       }
906     } else j++;
907     if (j==20 || j==24) fprintf(stdout, _("\n"));
908   }
909       
910   if ((MessageBuffer[6] & 1) == 1) fprintf(stdout,_("lock 1 closed\n"));
911   if ((MessageBuffer[6] & 2) == 2) fprintf(stdout,_("lock 2 closed\n"));
912   if ((MessageBuffer[6] & 4) == 4) fprintf(stdout,_("lock 3 closed\n"));
913   if ((MessageBuffer[6] & 8) == 8) fprintf(stdout,_("lock 4 closed\n"));
914
915   /* I'm not sure here at all */
916   if ((MessageBuffer[5] & 1) == 1) fprintf(stdout,_("lock 1 - user\n"));
917   if ((MessageBuffer[5] & 2) == 2) fprintf(stdout,_("lock 2 - user\n"));
918   if ((MessageBuffer[5] & 4) == 4) fprintf(stdout,_("lock 3 - user\n"));
919   if ((MessageBuffer[5] & 8) == 8) fprintf(stdout,_("lock 4 - user\n"));
920
921   fprintf(stdout,_("counter for lock1: %i\n"),MessageBuffer[21]);
922   fprintf(stdout,_("counter for lock2: %i\n"),MessageBuffer[22]);
923   fprintf(stdout,_("counter for lock3: %i\n"),MessageBuffer[23]);
924   fprintf(stdout,_("counter for lock4: %i\n"),MessageBuffer[24]);
925
926 #endif
927
928   j=0;
929   for (i=0; i < 12; i++)
930   {
931     if (j<24) {
932       uni[j]='0' + (MessageBuffer[9+i] >> 4);
933       j++;
934     }
935     if (j!=15) {
936       if (j<24) {
937         uni[j]='0' + (MessageBuffer[9+i] & 0x0f);
938         j++;
939       }
940     } else j++;
941   }
942
943   strncpy(CurrentSimLock->simlocks[0].data,uni,5);
944   CurrentSimLock->simlocks[0].data[5]=0;
945   strncpy(CurrentSimLock->simlocks[3].data,uni+5,10);
946   CurrentSimLock->simlocks[3].data[10]=0;
947   strncpy(CurrentSimLock->simlocks[1].data,uni+16,4);
948   CurrentSimLock->simlocks[1].data[4]=0;
949   strncpy(CurrentSimLock->simlocks[2].data,uni+20,4);
950   CurrentSimLock->simlocks[2].data[4]=0;                                    
951
952   CurrentSimLock->simlocks[0].enabled=((MessageBuffer[6] & 1) == 1);
953   CurrentSimLock->simlocks[1].enabled=((MessageBuffer[6] & 2) == 2);
954   CurrentSimLock->simlocks[2].enabled=((MessageBuffer[6] & 4) == 4);
955   CurrentSimLock->simlocks[3].enabled=((MessageBuffer[6] & 8) == 8);
956
957   CurrentSimLock->simlocks[0].factory=((MessageBuffer[5] & 1) != 1);
958   CurrentSimLock->simlocks[1].factory=((MessageBuffer[5] & 2) != 2);
959   CurrentSimLock->simlocks[2].factory=((MessageBuffer[5] & 4) != 4);
960   CurrentSimLock->simlocks[3].factory=((MessageBuffer[5] & 8) != 8);
961
962   CurrentSimLock->simlocks[0].counter=MessageBuffer[21];
963   CurrentSimLock->simlocks[1].counter=MessageBuffer[22];
964   CurrentSimLock->simlocks[2].counter=MessageBuffer[23];
965   CurrentSimLock->simlocks[3].counter=MessageBuffer[24];
966
967   CurrentSimlockInfoError=GE_NONE;
968 }
969
970 GSM_Error N6110_SimlockInfo(GSM_AllSimlocks *siml)
971 {
972   GSM_Error error;
973   unsigned char req[] = {0x00,0x01,0x8a,0x00};
974   error=N6110_EnableExtendedCommands(0x01);
975   if (error!=GE_NONE) return error;
976
977   CurrentSimLock=siml;
978  
979   return NULL_SendMessageSequence (50, &CurrentSimlockInfoError, 4, 0x40, req);  
980 }
981
982 void N6110_ReplyResetPhoneSettings(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
983
984 #ifdef DEBUG
985   fprintf(stdout, _("Message: Resetting phone settings\n"));
986 #endif /* DEBUG */
987
988   CurrentResetPhoneSettingsError=GE_NONE;
989 }
990
991 GSM_Error N6110_ResetPhoneSettings()
992 {
993   GSM_Error error;
994   unsigned char req[] = {0x00,0x01,0x65,0x08,0x00};  
995   error=N6110_EnableExtendedCommands(0x01);
996   if (error!=GE_NONE) return error;
997
998   return NULL_SendMessageSequence
999     (50, &CurrentResetPhoneSettingsError, 5, 0x40, req);  
1000 }
1001 GSM_Error N6110_GetManufacturer(char *manufacturer)
1002 {
1003         strcpy (manufacturer, "Nokia");
1004         return (GE_NONE);
1005 }
1006
1007 GSM_Error N6110_GetVoiceMailbox ( GSM_PhonebookEntry *entry)
1008 {
1009   unsigned char req[] = {N6110_FRAME_HEADER, 0x01, 0x00, 0x00, 0x00};
1010
1011   GSM_Error error;
1012   
1013   CurrentPhonebookEntry = entry;
1014
1015   req[4] = N6110_MEMORY_VOICE;
1016   req[5] = 0x00; /* Location - isn't important, but... */
1017
1018   error=NULL_SendMessageSequence
1019     (20, &CurrentPhonebookError, 7, 0x03, req);
1020     
1021   CurrentPhonebookEntry = NULL;
1022   
1023   return error;
1024 }
1025
1026 void N6110_ReplyGetOperatorName(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1027
1028   int i, count;
1029   
1030   GSM_Bitmap NullBitmap;
1031
1032   DecodeNetworkCode(MessageBuffer+5, NullBitmap.netcode);
1033   
1034   count=8;
1035
1036 #ifdef DEBUG
1037   fprintf(stdout, _("Message: Info about downloaded operator name received: %s network (for gnokii \"%s\", for phone \""),
1038           NullBitmap.netcode,
1039           GSM_GetNetworkName(NullBitmap.netcode));      
1040 #endif
1041       
1042   i=count;
1043   while (MessageBuffer[count]!=0) {
1044 #ifdef DEBUG
1045     fprintf(stdout,_("%c"),MessageBuffer[count]);
1046 #endif
1047     count++;
1048   }
1049       
1050  strcpy(CurrentGetOperatorNameNetwork->Code, NullBitmap.netcode);
1051  strncpy(CurrentGetOperatorNameNetwork->Name, MessageBuffer+i,count-i+1);
1052
1053 #ifdef DEBUG
1054   fprintf(stdout,_("\")\n"));
1055 #endif
1056           
1057   CurrentGetOperatorNameError=GE_NONE;
1058 }
1059
1060 GSM_Error N6110_GetOperatorName (GSM_Network *operator)
1061 {
1062   unsigned char req[] = { 0x00,0x01,0x8c,0x00};
1063
1064   GSM_Error error;
1065
1066   error=N6110_EnableExtendedCommands(0x01);
1067   if (error!=GE_NONE) return error;
1068
1069   CurrentGetOperatorNameNetwork = operator;
1070
1071   error=NULL_SendMessageSequence
1072     (20, &CurrentGetOperatorNameError, 4, 0x40, req);
1073
1074   CurrentGetOperatorNameNetwork = NULL;
1075   
1076   return error;
1077 }
1078
1079 void N6110_ReplySetOperatorName(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1080     
1081 #ifdef DEBUG
1082   fprintf(stdout, _("Message: Downloaded operator name changed\n"));
1083 #endif    
1084
1085   CurrentSetOperatorNameError=GE_NONE;      
1086 }
1087
1088 GSM_Error N6110_SetOperatorName (GSM_Network *operator)
1089 {
1090   unsigned char req[256] = { 0x00,0x01,0x8b,0x00,
1091                              0x00,0x00, /* MCC */
1092                              0x00};     /* MNC */
1093
1094   GSM_Error error;
1095
1096   error=N6110_EnableExtendedCommands(0x01);
1097   if (error!=GE_NONE) return error;
1098
1099   EncodeNetworkCode(req+4,operator->Code);
1100
1101   strncpy(req+7,operator->Name,200);
1102     
1103   return NULL_SendMessageSequence
1104     (20, &CurrentSetOperatorNameError, 8+strlen(operator->Name), 0x40, req);
1105 }
1106
1107 void N6110_ReplyGetMemoryStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1108
1109   switch (MessageBuffer[3]) {
1110
1111   case 0x08:
1112
1113 #ifdef DEBUG
1114     fprintf(stdout, _("Message: Memory status received:\n"));
1115
1116     fprintf(stdout, _("   Memory Type: %s\n"), N6110_MemoryType_String[MessageBuffer[4]]);
1117     fprintf(stdout, _("   Used: %d\n"), MessageBuffer[6]);
1118     fprintf(stdout, _("   Free: %d\n"), MessageBuffer[5]);
1119 #endif /* DEBUG */
1120
1121     CurrentMemoryStatus->Used = MessageBuffer[6];
1122     CurrentMemoryStatus->Free = MessageBuffer[5];
1123     CurrentMemoryStatusError = GE_NONE;
1124
1125     break;
1126
1127   case 0x09:
1128
1129 #ifdef DEBUG
1130     switch (MessageBuffer[4]) {
1131       case 0x6f:
1132         fprintf(stdout, _("Message: Memory status error, phone is probably powered off.\n"));break;
1133       case 0x7d:
1134         fprintf(stdout, _("Message: Memory status error, memory type not supported by phone model.\n"));break;
1135       case 0x8d:
1136         fprintf(stdout, _("Message: Memory status error, waiting for security code.\n"));break;
1137       default:
1138         fprintf(stdout, _("Message: Unknown Memory status error, subtype (MessageBuffer[4]) = %02x\n"),MessageBuffer[4]);break;
1139     }
1140 #endif
1141
1142     switch (MessageBuffer[4]) {
1143       case 0x6f:CurrentMemoryStatusError = GE_TIMEOUT;break;
1144       case 0x7d:CurrentMemoryStatusError = GE_INTERNALERROR;break;
1145       case 0x8d:CurrentMemoryStatusError = GE_INVALIDSECURITYCODE;break;
1146       default:break;
1147     }
1148
1149     break;
1150
1151   }
1152 }
1153
1154 /* This function is used to get storage status from the phone. It currently
1155    supports two different memory areas - internal and SIM. */
1156 GSM_Error N6110_GetMemoryStatus(GSM_MemoryStatus *Status)
1157 {
1158   unsigned char req[] = { N6110_FRAME_HEADER,
1159                           0x07, /* MemoryStatus request */
1160                           0x00  /* MemoryType */
1161                         };
1162
1163   GSM_Error error;
1164   
1165   CurrentMemoryStatus = Status;
1166
1167   req[4] = N6110_GetMemoryType(Status->MemoryType);
1168
1169   error=NULL_SendMessageSequence
1170     (20, &CurrentMemoryStatusError, 5, 0x03, req);
1171
1172   CurrentMemoryStatus = NULL;
1173
1174   return error;
1175 }
1176
1177 void N6110_ReplyGetNetworkInfo(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1178
1179   GSM_NetworkInfo NullNetworkInfo;
1180   
1181   /* Make sure we are expecting NetworkInfo frame */
1182   if (CurrentNetworkInfo && CurrentNetworkInfoError == GE_BUSY) {
1183 #ifdef DEBUG
1184     fprintf(stdout, _("Message: Network informations:\n"));
1185 #endif
1186   } else {
1187 #ifdef DEBUG
1188     fprintf(stdout, _("Message: Network informations not requested, but received:\n"));
1189 #endif
1190   }
1191       
1192   sprintf(NullNetworkInfo.NetworkCode, "%x%x%x %x%x", MessageBuffer[14] & 0x0f, MessageBuffer[14] >>4, MessageBuffer[15] & 0x0f, MessageBuffer[16] & 0x0f, MessageBuffer[16] >>4);
1193
1194   sprintf(NullNetworkInfo.CellID, "%02x%02x", MessageBuffer[10], MessageBuffer[11]);
1195
1196   sprintf(NullNetworkInfo.LAC, "%02x%02x", MessageBuffer[12], MessageBuffer[13]);
1197
1198 #ifdef DEBUG
1199   fprintf(stdout, _("   CellID: %s\n"), NullNetworkInfo.CellID);
1200   fprintf(stdout, _("   LAC: %s\n"), NullNetworkInfo.LAC);
1201   fprintf(stdout, _("   Network code: %s\n"), NullNetworkInfo.NetworkCode);
1202   fprintf(stdout, _("   Network name: %s (%s)\n"),
1203                      GSM_GetNetworkName(NullNetworkInfo.NetworkCode),
1204                      GSM_GetCountryName(NullNetworkInfo.NetworkCode));
1205   fprintf(stdout, _("   Status: "));
1206
1207   switch (MessageBuffer[8]) {
1208     case 0x01: fprintf(stdout, _("home network selected")); break;
1209     case 0x02: fprintf(stdout, _("roaming network")); break;
1210     case 0x03: fprintf(stdout, _("requesting network")); break;
1211     case 0x04: fprintf(stdout, _("not registered in the network")); break;
1212     default: fprintf(stdout, _("unknown"));
1213   }
1214
1215   fprintf(stdout, "\n");
1216
1217   fprintf(stdout, _("   Network selection: %s\n"), MessageBuffer[9]==1?_("manual"):_("automatic"));
1218 #endif /* DEBUG */
1219
1220   /* Make sure we are expecting NetworkInfo frame */
1221   if (CurrentNetworkInfo && CurrentNetworkInfoError == GE_BUSY)
1222     *CurrentNetworkInfo=NullNetworkInfo;
1223
1224   CurrentNetworkInfoError = GE_NONE;      
1225 }
1226
1227 GSM_Error N6110_GetNetworkInfo(GSM_NetworkInfo *NetworkInfo)
1228 {
1229   unsigned char req[] = { N6110_FRAME_HEADER,
1230                           0x70
1231                         };
1232
1233   GSM_Error error;
1234   
1235   CurrentNetworkInfo = NetworkInfo;
1236   
1237   error=NULL_SendMessageSequence
1238     (20, &CurrentNetworkInfoError, 4, 0x0a, req);
1239
1240   CurrentNetworkInfo = NULL;
1241
1242   return error;
1243 }
1244
1245 void N6110_ReplyGetProductProfileSetting(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1246
1247   int i;
1248   
1249 #ifdef DEBUG
1250   fprintf(stdout, _("Message: Product Profile Settings received -"));
1251   for (i=0;i<4;i++) fprintf(stdout, _(" %02x"),MessageBuffer[3+i]);
1252   fprintf(stdout, _("\n"));  
1253 #endif
1254
1255   for (i=0;i<4;i++) CurrentPPS[i]=MessageBuffer[3+i];
1256
1257   CurrentProductProfileSettingsError=GE_NONE;      
1258 }
1259
1260 GSM_Error N6110_GetProductProfileSetting (GSM_PPS *PPS)
1261 {
1262   unsigned char req[] = { 0x00, 0x01,0x6a };
1263   
1264   int i,j;
1265
1266   GSM_Error error;
1267
1268   error=N6110_EnableExtendedCommands(0x01);
1269   if (error!=GE_NONE) return error;
1270
1271   error=NULL_SendMessageSequence
1272     (20, &CurrentProductProfileSettingsError, 3, 0x40, req);
1273   if (error!=GE_NONE) return error;    
1274   
1275   switch (PPS->Name) {
1276     case PPS_ALS      : PPS->bool_value=(CurrentPPS[1]&32); break;
1277     case PPS_GamesMenu: PPS->bool_value=(CurrentPPS[3]&64); break;
1278     case PPS_HRData   : PPS->bool_value=(CurrentPPS[0]&64); break;
1279     case PPS_14400Data: PPS->bool_value=(CurrentPPS[0]&128);break;
1280     case PPS_EFR      : PPS->int_value =(CurrentPPS[0]&1)    +(CurrentPPS[0]&2);    break;
1281     case PPS_FR       : PPS->int_value =(CurrentPPS[0]&16)/16+(CurrentPPS[0]&32)/16;break;
1282     case PPS_HR       : PPS->int_value =(CurrentPPS[0]&4)/4  +(CurrentPPS[0]&8)/4;  break;
1283     case PPS_VibraMenu: PPS->bool_value=(CurrentPPS[4]&64); break;
1284     case PPS_LCDContrast:
1285          PPS->int_value=0;
1286          j=1;
1287          for (i=0;i<5;i++) {
1288            if (CurrentPPS[3]&j) PPS->int_value=PPS->int_value+j;
1289            j=j*2;
1290          }
1291          PPS->int_value=PPS->int_value*100/32;
1292          break;
1293
1294   }
1295   
1296   return (GE_NONE);
1297 }
1298
1299 void N6110_ReplySetProductProfileSetting(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1300
1301 #ifdef DEBUG
1302   int i;
1303   
1304   fprintf(stdout, _("Message: Product Profile Settings set to"));
1305   for (i=0;i<4;i++) fprintf(stdout, _(" %02x"),CurrentPPS[i]);
1306   fprintf(stdout, _("\n"));  
1307 #endif
1308      
1309   CurrentProductProfileSettingsError=GE_NONE;     
1310 }
1311
1312 GSM_Error N6110_SetProductProfileSetting (GSM_PPS *PPS)
1313 {
1314   unsigned char req[] = { 0x00, 0x01,0x6b, 
1315                           0x00, 0x00, 0x00, 0x00 }; /* bytes with Product Profile Setings */
1316   unsigned char settings[32];
1317   
1318   GSM_PPS OldPPS;
1319   
1320   int i,j,z;
1321   
1322   GSM_Error error;
1323
1324   error=N6110_EnableExtendedCommands(0x01);
1325   if (error!=GE_NONE) return error;
1326   
1327   OldPPS.Name=PPS_ALS;
1328   error=N6110_GetProductProfileSetting(&OldPPS);
1329   if (error!=GE_NONE) return error;
1330   
1331   j=128;z=0;
1332   for (i=0;i<32;i++) {
1333     if (CurrentPPS[z]&j)
1334       settings[i]='1';
1335     else
1336       settings[i]='0';    
1337     if (j==1) {
1338       j=128;
1339       z++;
1340     } else j=j/2;
1341   }
1342   
1343 #ifdef DEBUG
1344   fprintf(stdout,_("Current settings: "));
1345   for (i=0;i<32;i++) {
1346     fprintf(stdout,_("%c"),settings[i]);    
1347   }
1348   fprintf(stdout,_("\n"));
1349 #endif
1350
1351   switch (PPS->Name) {
1352     case PPS_ALS      :settings[10]=PPS->bool_value?'1':'0';break;
1353     case PPS_HRData   :settings[ 5]=PPS->bool_value?'1':'0';break;
1354     case PPS_14400Data:settings[ 6]=PPS->bool_value?'1':'0';break;
1355     default           :break;
1356   }
1357     
1358   j=128;z=0;
1359   for (i=0;i<32;i++) {
1360     if (settings[i]=='1') req[z+3]=req[z+3]+j;
1361     if (j==1) {
1362       j=128;
1363       z++;
1364     } else j=j/2;
1365   }  
1366
1367 #ifdef DEBUG
1368   fprintf(stdout,_("Current settings: "));
1369   for (i=0;i<4;i++) {
1370     fprintf(stdout,_("%i "),req[i+3]);    
1371   }
1372   fprintf(stdout,_("\n"));
1373 #endif
1374
1375   for (i=0;i<4;i++) {
1376    CurrentPPS[i]=req[i+3];    
1377   }
1378
1379   return NULL_SendMessageSequence
1380     (20, &CurrentProductProfileSettingsError, 7, 0x40, req);
1381 }
1382
1383 void N6110_ReplyPressKey(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1384
1385     if (MessageBuffer[4]==CurrentPressKeyEvent) CurrentPressKeyError=GE_NONE;
1386                                            else CurrentPressKeyError=GE_UNKNOWN; /* MessageBuffer[4] = 0x05 */
1387 #ifdef DEBUG
1388     fprintf(stdout, _("Message: Result of key "));
1389     switch (MessageBuffer[4])
1390     {
1391       case PRESSPHONEKEY:   fprintf(stdout, _("press OK\n"));break;
1392       case RELEASEPHONEKEY: fprintf(stdout, _("release OK\n"));break;
1393       default:              fprintf(stdout, _("press or release - error\n"));break;
1394     }
1395 #endif /* DEBUG */
1396 }
1397
1398 GSM_Error N6110_PressKey(int key, int event)
1399 {
1400   unsigned char req[] = {N6110_FRAME_HEADER, 0x42, 0x01, 0x00, 0x01};
1401   
1402   req[4]=event; /* if we press or release key */
1403   req[5]=key;
1404   
1405   CurrentPressKeyEvent=event;
1406   
1407   return NULL_SendMessageSequence
1408     (10, &CurrentPressKeyError, 7, 0x0c, req);
1409 }
1410
1411 void N6110_ReplyDisplayOutput(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1412
1413   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
1414   char model[64];
1415
1416   int i, j;
1417
1418   char uni[100];
1419     
1420   switch(MessageBuffer[3]) {
1421
1422   /* Phone sends displayed texts */
1423   case 0x50:
1424     NewX=MessageBuffer[6];
1425     NewY=MessageBuffer[5];
1426
1427     DecodeUnicode (uni, MessageBuffer+8, MessageBuffer[7]);
1428
1429 #ifdef DEBUG
1430     fprintf(stdout, _("New displayed text (%i %i): \"%s\"\n"),NewX,NewY,uni);      
1431 #endif /* DEBUG */
1432
1433     while (N6110_GetModel(model)  != GE_NONE)
1434       sleep(1);
1435
1436     /* With these rules it works almost excellent with my N5110 */
1437     /* I don't have general rule :-(, that's why you must experiment */
1438     /* with your phone. Nokia could make it better. MW */
1439     /* It's almost OK for N5110*/
1440     /* FIX ME: it will be the same for N5130 and 3210 too*/
1441     if (!strcmp(model,"NSE-1"))
1442     {
1443       /* OldX==1000 means - it's first time */
1444       if (OldX==1000) {
1445       
1446         /* Clean table */
1447         for (i=0;i<5+1;i++) {
1448           for (j=0;j<27+1;j++) {PhoneScreen[i][j]=' ';}
1449       }
1450       OldX=0;
1451     }
1452
1453     if ((OldX==0 && OldY==31 && NewX==29 && NewY==46) ||
1454         (OldX==0 && OldY==13 && NewX==23 && NewY==46)) {
1455       /* Clean the line with current text */
1456       for (j=0;j<27+1;j++) {PhoneScreen[NewY/(47/5)][j]=' ';}
1457       
1458       /* Inserts text into table */
1459       for (i=0; i<MessageBuffer[7];i++) {       
1460         PhoneScreen[NewY/(47/5)][NewX/(84/27)+i]=uni[i];
1461       }
1462
1463     }
1464
1465     if ((OldX==0 && OldY==21 && NewX==0 && NewY==10) ||
1466         (OldX==0 && OldY==10 && NewX==35 && NewY==46)) {
1467     } else {
1468       if ((OldX!=0 && NewX==0 && NewY!=6) ||
1469           (OldX==0 && NewX!=0 && OldY!=13 && OldY!=22) ||
1470           (OldX==0 && NewX==0 && NewY<OldY && (NewY!=13 || OldY!=26)) ||
1471           (OldY==5 && NewY!=5) ||
1472           (OldX==0 && OldY==13 && NewX==23 && NewY==46)) {
1473
1474         /* Writes "old" screen */
1475         for (i=0;i<5+1;i++) {
1476           for (j=0;j<27+1;j++) {fprintf(stdout,_("%c"),PhoneScreen[i][j]);}
1477             fprintf(stdout,_("\n"));
1478           }
1479         
1480           /* Clean table */
1481           for (i=0;i<5+1;i++) {
1482             for (j=0;j<27+1;j++) {PhoneScreen[i][j]=' ';}
1483           }
1484         }
1485       }
1486       
1487       /* Clean the line with current text */
1488       for (j=0;j<27+1;j++) {PhoneScreen[NewY/(47/5)][j]=' ';}
1489       
1490       /* Inserts text into table */
1491       for (i=0; i<MessageBuffer[7];i++) {       
1492         PhoneScreen[NewY/(47/5)][NewX/(84/27)+i]=uni[i];
1493       }
1494       
1495       OldY=NewY;
1496       OldX=NewX;
1497     } else {
1498 #ifndef DEBUG
1499       fprintf(stdout, _("%s\n"),uni);      
1500 #endif
1501     }
1502
1503     break;
1504  
1505   case 0x54:
1506       
1507     if (MessageBuffer[4]==1)
1508     {
1509       
1510 #ifdef DEBUG
1511       fprintf(stdout, _("Display output successfully disabled/enabled.\n"));
1512 #endif /* DEBUG */
1513
1514       CurrentDisplayOutputError=GE_NONE;
1515     }
1516        
1517     break;
1518   }
1519 }
1520
1521 GSM_Error SetDisplayOutput(unsigned char state)
1522 {
1523   unsigned char req[] = { N6110_FRAME_HEADER,
1524                           0x53, 0x00};
1525
1526   req[4]=state;
1527   
1528   return NULL_SendMessageSequence
1529     (30, &CurrentDisplayOutputError, 5, 0x0d, req);
1530 }
1531
1532 GSM_Error N6110_EnableDisplayOutput()
1533 {
1534   return SetDisplayOutput(0x01);
1535 }
1536  
1537 GSM_Error N6110_DisableDisplayOutput()
1538 {
1539   return SetDisplayOutput(0x02);
1540 }
1541
1542 /* If it is interesting for somebody: we can use 0x40 msg for it
1543    and it will work for all phones. See n6110.txt for details */
1544 GSM_Error N6110_AnswerCall(char s)
1545 {
1546         unsigned char req0[] = { N6110_FRAME_HEADER, 0x42,0x05,0x01,0x07,                                0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
1547                             0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80};
1548         unsigned char req[] = { N6110_FRAME_HEADER, 0x06, 0x00, 0x00};
1549
1550         req[4]=s;
1551
1552 #ifdef DEBUG
1553         fprintf(stdout,_("Answering call %d\n\r"),s);
1554 #endif
1555
1556         Protocol->SendMessage(sizeof(req0), 0x01, req0);
1557         sleep(1);
1558
1559         return NULL_SendMessageSequence
1560                 (20, &CurrentMagicError, sizeof(req) , 0x01, req);
1561 }
1562
1563 void N6110_ReplyGetProfile(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1564
1565   switch (MessageBuffer[3]) {
1566
1567   /* Profile feature */
1568   case 0x14:   
1569
1570     switch(GetModelFeature (FN_PROFILES)) {
1571       case F_PROF33:
1572         switch (MessageBuffer[6]) {
1573           case 0x00: CurrentProfile->KeypadTone  = MessageBuffer[8]; break;
1574           case 0x01: CurrentProfile->CallAlert   = MessageBuffer[8]; break;
1575           case 0x02: CurrentProfile->Ringtone    = MessageBuffer[8]; break;
1576           case 0x03: CurrentProfile->Volume      = MessageBuffer[8]; break;
1577           case 0x04: CurrentProfile->MessageTone = MessageBuffer[8]; break;
1578           case 0x05: CurrentProfile->Vibration   = MessageBuffer[8]; break;
1579           case 0x06: CurrentProfile->WarningTone = MessageBuffer[8]; break;
1580           case 0x07: CurrentProfile->ScreenSaver = MessageBuffer[8]; break;       
1581           default:
1582 #ifdef DEBUG
1583             fprintf(stdout,_("feature %i = value %i\n\n"),MessageBuffer[6],MessageBuffer[8]);
1584 #endif
1585             break;
1586         }
1587         break;
1588       default:
1589         switch (MessageBuffer[6]) {
1590           case 0x00: CurrentProfile->KeypadTone      = MessageBuffer[8];break;
1591           case 0x01: CurrentProfile->Lights          = MessageBuffer[8];break;
1592           case 0x02: CurrentProfile->CallAlert       = MessageBuffer[8];break;
1593           case 0x03: CurrentProfile->Ringtone        = MessageBuffer[8];break;
1594           case 0x04: CurrentProfile->Volume          = MessageBuffer[8];break;
1595           case 0x05: CurrentProfile->MessageTone     = MessageBuffer[8];break;
1596           case 0x06: CurrentProfile->Vibration       = MessageBuffer[8];break;
1597           case 0x07: CurrentProfile->WarningTone     = MessageBuffer[8];break;
1598           case 0x08: CurrentProfile->CallerGroups    = MessageBuffer[8];break;
1599           case 0x09: CurrentProfile->AutomaticAnswer = MessageBuffer[8];break;
1600           default:
1601 #ifdef DEBUG
1602             fprintf(stdout,_("feature %i = value %i\n\n"),MessageBuffer[6],MessageBuffer[8]);
1603 #endif
1604             break;
1605         }
1606         break;
1607     }
1608
1609     CurrentProfileError = GE_NONE;
1610     break;
1611
1612   /* Incoming profile name */
1613   case 0x1b:   
1614
1615     if (MessageBuffer[9] == 0x00) {
1616       CurrentProfile->DefaultName=MessageBuffer[8];
1617     } else {
1618       CurrentProfile->DefaultName=-1;      
1619         
1620       /* Here name is in Unicode */
1621       if (GetModelFeature (FN_PROFILES)==F_PROF33) {
1622         DecodeUnicode (CurrentProfile->Name, MessageBuffer+10, MessageBuffer[9]/2);
1623       } else {
1624         /* ...here not */
1625         sprintf(CurrentProfile->Name, MessageBuffer + 10, MessageBuffer[9]);
1626         CurrentProfile->Name[MessageBuffer[9]] = '\0';
1627       }
1628     }
1629
1630     CurrentProfileError = GE_NONE;
1631     break;
1632
1633   }
1634 }
1635
1636 /* Needs SIM card with PIN in phone */
1637 GSM_Error N6110_GetProfile(GSM_Profile *Profile)
1638 {
1639   int i;
1640   
1641   unsigned char name_req[] = { N6110_FRAME_HEADER, 0x1a, 0x00};
1642   unsigned char feat_req[] = { N6110_FRAME_HEADER, 0x13, 0x01, 0x00, 0x00};
1643
1644   GSM_Error error;
1645   
1646   CurrentProfile = Profile;
1647
1648   /* When after sending all frames feature==253, it means, that it is not
1649      supported */
1650   CurrentProfile->KeypadTone=253;
1651   CurrentProfile->Lights=253;    
1652   CurrentProfile->CallAlert=253; 
1653   CurrentProfile->Ringtone=253;  
1654   CurrentProfile->Volume=253;    
1655   CurrentProfile->MessageTone=253;
1656   CurrentProfile->WarningTone=253;
1657   CurrentProfile->Vibration=253;  
1658   CurrentProfile->CallerGroups=253;
1659   CurrentProfile->ScreenSaver=253; 
1660   CurrentProfile->AutomaticAnswer=253;
1661
1662   name_req[4] = Profile->Number;
1663
1664   error=NULL_SendMessageSequence
1665     (20, &CurrentProfileError, 5, 0x05, name_req);
1666   if (error!=GE_NONE) return error;
1667
1668   for (i = 0x00; i <= 0x09; i++) {
1669
1670     feat_req[5] = Profile->Number;
1671     
1672     feat_req[6] = i;
1673
1674     error=NULL_SendMessageSequence
1675       (20, &CurrentProfileError, 7, 0x05, feat_req);
1676     if (error!=GE_NONE) return error;
1677   }
1678
1679   if (Profile->DefaultName > -1)
1680   {
1681     switch(GetModelFeature (FN_PROFILES)) {
1682       case F_PROF33:
1683         switch (Profile->DefaultName) {
1684           case 0x00: sprintf(Profile->Name, "General");break;
1685           case 0x01: sprintf(Profile->Name, "Silent");break;
1686           case 0x02: sprintf(Profile->Name, "Descreet");break;
1687           case 0x03: sprintf(Profile->Name, "Loud");break;
1688           case 0x04: sprintf(Profile->Name, "My style");break;
1689           case 0x05: Profile->Name[0]=0;break;
1690           default  : sprintf(Profile->Name, "Unknown (%i)", Profile->DefaultName);break;
1691         }
1692         break;
1693       case F_PROF51:
1694         switch (Profile->DefaultName) {
1695           case 0x00: sprintf(Profile->Name, "Personal");break;
1696           case 0x01: sprintf(Profile->Name, "Car");break;
1697           case 0x02: sprintf(Profile->Name, "Headset");break;
1698           default  : sprintf(Profile->Name, "Unknown (%i)", Profile->DefaultName);break;
1699         }
1700         break;
1701       case F_PROF61:
1702         switch (Profile->DefaultName) {
1703           case 0x00: sprintf(Profile->Name, "General");break;
1704           case 0x01: sprintf(Profile->Name, "Silent");break;
1705           case 0x02: sprintf(Profile->Name, "Meeting");break;
1706           case 0x03: sprintf(Profile->Name, "Outdoor");break;
1707           case 0x04: sprintf(Profile->Name, "Pager");break;
1708           case 0x05: sprintf(Profile->Name, "Car");break;
1709           case 0x06: sprintf(Profile->Name, "Headset");break;
1710           default  : sprintf(Profile->Name, "Unknown (%i)", Profile->DefaultName);break;
1711         }
1712         break;
1713     }
1714   }
1715   
1716   return (GE_NONE);
1717
1718 }
1719
1720 void N6110_ReplySetProfile(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1721
1722   switch (MessageBuffer[3]) {
1723
1724   /* Profile feature change result */
1725   case 0x11:   
1726 #ifdef DEBUG
1727     fprintf(stdout, _("Message: Profile feature change result.\n"));
1728 #endif /* DEBUG */
1729     CurrentProfileError = GE_NONE;
1730     break;
1731
1732   /* Profile name set result */
1733   case 0x1d:   
1734 #ifdef DEBUG
1735     fprintf(stdout, _("Message: Profile name change result.\n"));
1736 #endif /* DEBUG */
1737     CurrentProfileError = GE_NONE;
1738     break;
1739
1740   }
1741 }
1742
1743 GSM_Error N6110_SetProfileFeature(u8 profile, u8 feature, u8 value)
1744 {
1745   unsigned char feat_req[] = { N6110_FRAME_HEADER, 0x10, 0x01,
1746                                0x00, 0x00, 0x00};
1747
1748   feat_req[5]=profile;
1749   feat_req[6]=feature;
1750   feat_req[7]=value;
1751
1752   return NULL_SendMessageSequence
1753     (20, &CurrentProfileError, 8, 0x05, feat_req);
1754 }
1755
1756 GSM_Error N6110_SetProfile(GSM_Profile *Profile)
1757 {
1758   int i,value;
1759
1760   unsigned char name_req[40] = { N6110_FRAME_HEADER, 0x1c, 0x01, 0x03,
1761                                  0x00, 0x00, 0x00};
1762
1763   GSM_Error error;
1764   
1765   name_req[7] = Profile->Number;
1766   name_req[8] = strlen(Profile->Name);
1767   name_req[6] = name_req[8] + 2;
1768
1769   for (i = 0; i < name_req[8]; i++)
1770     name_req[9 + i] = Profile->Name[i];
1771
1772   error=NULL_SendMessageSequence
1773     (20, &CurrentProfileError, name_req[8] + 9, 0x05, name_req);
1774   if (error!=GE_NONE) return error;
1775
1776   for (i = 0x00; i <= 0x09; i++) {
1777
1778     switch (i) {
1779       case 0x00: value = Profile->KeypadTone; break;
1780       case 0x01: value = Profile->Lights; break;
1781       case 0x02: value = Profile->CallAlert; break;
1782       case 0x03: value = Profile->Ringtone; break;
1783       case 0x04: value = Profile->Volume; break;
1784       case 0x05: value = Profile->MessageTone; break;
1785       case 0x06: value = Profile->Vibration; break;
1786       case 0x07: value = Profile->WarningTone; break;
1787       case 0x08: value = Profile->CallerGroups; break;
1788       case 0x09: value = Profile->AutomaticAnswer; break;
1789       default  : value = 0; break;
1790     }
1791
1792     error=N6110_SetProfileFeature(Profile->Number,i,value);
1793     if (error!=GE_NONE) return error;
1794   }
1795
1796   return (GE_NONE);
1797 }
1798
1799 bool N6110_SendRLPFrame(RLP_F96Frame *frame, bool out_dtx)
1800 {
1801   u8 req[60] = { 0x00, 0xd9 };
1802                 
1803   /* Discontinuos transmission (DTX).  See section 5.6 of GSM 04.22 version
1804      7.0.1. */
1805        
1806   if (out_dtx)
1807     req[1]=0x01;
1808
1809   memcpy(req+2, (u8 *) frame, 32);
1810
1811   return (Protocol->SendFrame(32, 0xf0, req));
1812 }
1813
1814 void N6110_ReplyGetCalendarNote(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1815
1816   int i, j;
1817
1818   u8 mychar1;
1819
1820   wchar_t wc;  
1821     
1822   switch (MessageBuffer[4]) {
1823
1824     case 0x01:
1825       
1826       CurrentCalendarNote->Type=MessageBuffer[8];
1827
1828       DecodeDateTime(MessageBuffer+9, &CurrentCalendarNote->Time);
1829
1830       DecodeDateTime(MessageBuffer+16, &CurrentCalendarNote->Alarm);
1831
1832       CurrentCalendarNote->Text[0]=0;
1833       
1834       if (GetModelFeature (FN_CALENDAR)==F_CAL33) {
1835         i=0;
1836         if (CurrentCalendarNote->Type == GCN_REMINDER) i=1; //first char is subset
1837         switch (MessageBuffer[24]) {
1838           case 3:
1839 #ifdef DEBUG
1840             fprintf(stdout,_("Subset 3 in reminder note !\n"));
1841 #endif
1842             while (i!=MessageBuffer[23]) {
1843               j=0;
1844               if (i!=MessageBuffer[23]-1) {
1845                 if (MessageBuffer[24+i]>=0xc2) {
1846                   DecodeWithUTF8Alphabet(MessageBuffer[24+i], MessageBuffer[24+i+1], &mychar1);
1847                   CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)+1]=0;
1848                   CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)]=mychar1;
1849                   j=-1;
1850                   i++;
1851                 }
1852               }
1853               if (j!=-1) {
1854                 CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)+1]=0;
1855                 CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)]=MessageBuffer[24+i];
1856               }
1857               i++;
1858             }
1859             break;
1860           case 2:
1861 #ifdef DEBUG
1862             fprintf(stdout,_("Subset 2 in reminder note !\n"));
1863 #endif
1864             while (i!=MessageBuffer[23]) {
1865               wc = MessageBuffer[24+i] | (0x00 << 8);
1866               CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)+1]=0;
1867               CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)]=
1868                       DecodeWithUnicodeAlphabet(wc);
1869               i++;
1870             }
1871             break;
1872           case 1:
1873 #ifdef DEBUG
1874             fprintf(stdout,_("Subset 1 in reminder note !\n"));
1875 #endif
1876             memcpy(CurrentCalendarNote->Text,MessageBuffer+24+i,MessageBuffer[23]-i);
1877             CurrentCalendarNote->Text[MessageBuffer[23]-i]=0;
1878             break;
1879           default:
1880 #ifdef DEBUG
1881             fprintf(stdout,_("Unknown subset in reminder note !\n"));
1882 #endif
1883             memcpy(CurrentCalendarNote->Text,MessageBuffer+24+i,MessageBuffer[23]-i);
1884             CurrentCalendarNote->Text[MessageBuffer[23]-i]=0;
1885             break;
1886         }
1887       } else {
1888         memcpy(CurrentCalendarNote->Text,MessageBuffer+24,MessageBuffer[23]);
1889         CurrentCalendarNote->Text[MessageBuffer[23]]=0;
1890       }
1891       
1892       if (CurrentCalendarNote->Type == GCN_CALL) {
1893         memcpy(CurrentCalendarNote->Phone,MessageBuffer+24+MessageBuffer[23]+1,MessageBuffer[24+MessageBuffer[23]]);
1894         CurrentCalendarNote->Phone[MessageBuffer[24+MessageBuffer[23]]]=0;
1895       }
1896
1897       CurrentCalendarNote->Recurrance=0;
1898
1899       CurrentCalendarNote->AlarmType=0;
1900
1901 #ifdef DEBUG
1902       fprintf(stdout, _("Message: Calendar note received.\n"));
1903
1904       fprintf(stdout, _("   Date: %d-%02d-%02d\n"), CurrentCalendarNote->Time.Year,
1905                                            CurrentCalendarNote->Time.Month,
1906                                            CurrentCalendarNote->Time.Day);
1907
1908       fprintf(stdout, _("   Time: %02d:%02d:%02d\n"), CurrentCalendarNote->Time.Hour,
1909                                            CurrentCalendarNote->Time.Minute,
1910                                            CurrentCalendarNote->Time.Second);
1911
1912       /* Some messages do not have alarm set up */
1913       if (CurrentCalendarNote->Alarm.Year != 0) {
1914         fprintf(stdout, _("   Alarm date: %d-%02d-%02d\n"), CurrentCalendarNote->Alarm.Year,
1915                                                  CurrentCalendarNote->Alarm.Month,
1916                                                  CurrentCalendarNote->Alarm.Day);
1917
1918         fprintf(stdout, _("   Alarm time: %02d:%02d:%02d\n"), CurrentCalendarNote->Alarm.Hour,
1919                                                  CurrentCalendarNote->Alarm.Minute,
1920                                                  CurrentCalendarNote->Alarm.Second);
1921       }
1922
1923       fprintf(stdout, _("   Type: %d\n"), CurrentCalendarNote->Type);
1924       fprintf(stdout, _("   Text: %s\n"), CurrentCalendarNote->Text);
1925
1926       if (CurrentCalendarNote->Type == GCN_CALL)
1927         fprintf(stdout, _("   Phone: %s\n"), CurrentCalendarNote->Phone);
1928 #endif /* DEBUG */
1929
1930       CurrentCalendarNoteError=GE_NONE;
1931       break;
1932
1933     case 0x93:
1934
1935 #ifdef DEBUG
1936       fprintf(stdout, _("Message: Calendar note not available\n"));
1937 #endif /* DEBUG */
1938
1939       CurrentCalendarNoteError=GE_INVALIDCALNOTELOCATION;
1940       break;
1941
1942     default:
1943
1944 #ifdef DEBUG
1945       fprintf(stdout, _("Message: Calendar note error\n"));
1946 #endif /* DEBUG */
1947
1948       CurrentCalendarNoteError=GE_INTERNALERROR;
1949       break;
1950
1951   }
1952 }
1953
1954 GSM_Error N6110_GetCalendarNote(GSM_CalendarNote *CalendarNote)
1955 {
1956
1957   unsigned char req[] = { N6110_FRAME_HEADER,
1958                           0x66, 0x00
1959                         };
1960   GSM_Error error;
1961
1962   req[4]=CalendarNote->Location;
1963
1964   CurrentCalendarNote = CalendarNote;
1965
1966   error=NULL_SendMessageSequence
1967     (20, &CurrentCalendarNoteError, 5, 0x13, req);
1968
1969   CurrentCalendarNote = NULL;
1970
1971   return error;
1972 }
1973
1974 void N6110_ReplyWriteCalendarNote(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1975
1976 #ifdef DEBUG
1977   switch(MessageBuffer[4]) {
1978     /* This message is also sent when the user enters the new entry on keypad */
1979     case 0x01:
1980       fprintf(stdout, _("Message: Calendar note write succesfull!\n"));break;      
1981     case 0x73:
1982       fprintf(stdout, _("Message: Calendar note write failed!\n"));break;
1983     case 0x7d:
1984       fprintf(stdout, _("Message: Calendar note write failed!\n"));break;
1985     default:
1986       fprintf(stdout, _("Unknown message of type 0x13 and subtype 0x65\n"));break;
1987   }
1988 #endif
1989
1990   switch(MessageBuffer[4]) {
1991     case 0x01: CurrentCalendarNoteError=GE_NONE; break;      
1992     case 0x73: CurrentCalendarNoteError=GE_INTERNALERROR; break;
1993     case 0x7d: CurrentCalendarNoteError=GE_INTERNALERROR; break;
1994     default  : AppendLogText("Unknown msg\n",false); break;
1995   }
1996 }
1997
1998 GSM_Error N6110_WriteCalendarNote(GSM_CalendarNote *CalendarNote)
1999 {
2000
2001   unsigned char req[200] = { N6110_FRAME_HEADER,
2002                              0x64, 0x01, 0x10,
2003                              0x00, /* Length of the rest of the frame. */
2004                              0x00, /* The type of calendar note */
2005                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2006                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2007                         };
2008
2009   typedef struct {
2010     char *model;
2011     unsigned char call;
2012     unsigned char meeting;
2013     unsigned char birthday;
2014     unsigned char reminder;
2015   } calendar_model_length;
2016   
2017   /* Length of entries */
2018   calendar_model_length calendar_lengths[] =
2019   {
2020     /*model,CallTo,Meeting,Birthday,Reminder*/
2021     {"NHM-5",0x24,0x24,0x24,0x24}, //Reminder from phone, other quesses
2022     {"NHM-6",0x24,0x24,0x24,0x24}, //Reminder from phone, other quesses
2023     {"NSE-3",0x1e,0x14,0x14,0x1e}, //from NCDS3 [HKEY_LOCAL_MACHINE\Software\Nokia\Data Suite\3.0\Calendar]
2024     {"NSM-1",0x1e,0x18,0x18,0x24}, //from NCDS3 
2025     {"NSK-3",0x1e,0x14,0x14,0x1e}, //from NCDS3 
2026     {"NSB-3",0x20,0x14,0x14,0x1e}, //from NCDS3
2027     {"",     0,   0,   0,   0   }  //end of table
2028   };
2029
2030   int i, j, current;
2031
2032   u8 mychar;
2033   
2034   u8 mychar1,mychar2;
2035   
2036   GSM_Error error;
2037   
2038   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
2039   char model[64];
2040
2041   req[7]=CalendarNote->Type;
2042
2043   EncodeDateTime(req+8, &CalendarNote->Time);
2044   req[14] = CalendarNote->Time.Timezone;
2045
2046   if (CalendarNote->Alarm.Year) {
2047     EncodeDateTime(req+15, &CalendarNote->Alarm);
2048     req[21] = CalendarNote->Alarm.Timezone;
2049   }
2050
2051   req[22]=strlen(CalendarNote->Text);
2052   
2053   current=23;
2054
2055   if (GetModelFeature (FN_CALENDAR)==F_CAL33 && CalendarNote->Type==GCN_REMINDER) {
2056     req[22]++;           // one additional char
2057     req[current++]=0x01; //we use now subset 1
2058   }
2059     
2060   for (i=0; i<strlen(CalendarNote->Text); i++) {
2061     j=0;
2062     mychar=CalendarNote->Text[i];
2063     if (GetModelFeature (FN_CALENDAR)==F_CAL33 && CalendarNote->Type==GCN_REMINDER) {
2064       if (EncodeWithUTF8Alphabet(mychar,&mychar1,&mychar2)) {
2065           req[current++]=mychar1;
2066           req[current++]=mychar2;
2067           req[23]=0x03; //use subset 3
2068           req[22]++;    // one additional char
2069           j=-1;
2070       }
2071     }
2072     if (j!=-1) {
2073       /* Enables/disables blinking */
2074       if (mychar=='~') req[current++]=0x01;
2075                   else req[current++]=mychar;
2076     }
2077   }
2078
2079   req[current++]=strlen(CalendarNote->Phone);
2080
2081   for (i=0; i<strlen(CalendarNote->Phone); i++)
2082     req[current++]=CalendarNote->Phone[i];
2083
2084   while (N6110_GetModel(model)  != GE_NONE)
2085     sleep(1);
2086
2087   /* Checking maximal length */
2088   i=0;
2089   while (strcmp(calendar_lengths[i].model,"")) {
2090     if (!strcmp(calendar_lengths[i].model,model)) {
2091       switch (CalendarNote->Type) {
2092         case GCN_REMINDER:if (req[22]>calendar_lengths[i].reminder) return GE_TOOLONG;break;
2093         case GCN_MEETING :if (req[22]>calendar_lengths[i].meeting)  return GE_TOOLONG;break;
2094         case GCN_BIRTHDAY:if (req[22]>calendar_lengths[i].birthday) return GE_TOOLONG;break;
2095         case GCN_CALL    :if (strlen(CalendarNote->Phone)>calendar_lengths[i].call) return GE_TOOLONG;break;
2096       }
2097       break;
2098     }
2099     i++;
2100   }
2101
2102   CurrentCalendarNote = CalendarNote;
2103
2104   error=NULL_SendMessageSequence
2105     (20, &CurrentCalendarNoteError, current, 0x13, req);
2106
2107   CurrentCalendarNote = NULL;
2108
2109   return error;
2110 }
2111
2112 void N6110_ReplyDeleteCalendarNote(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2113
2114 #ifdef DEBUG
2115   switch (MessageBuffer[4]) {
2116     /* This message is also sent when the user deletes an old entry on
2117        keypad or moves an old entry somewhere (there is also `write'
2118        message). */
2119     case 0x01:fprintf(stdout, _("Message: Calendar note deleted\n"));break;
2120     case 0x93:fprintf(stdout, _("Message: Calendar note can't be deleted\n"));break;
2121     default  :fprintf(stdout, _("Message: Calendar note deleting error\n"));break;
2122   }
2123 #endif
2124
2125   switch (MessageBuffer[4]) {
2126     case 0x01:CurrentCalendarNoteError=GE_NONE;break;
2127     case 0x93:CurrentCalendarNoteError=GE_INVALIDCALNOTELOCATION;break;
2128     default  :CurrentCalendarNoteError=GE_INTERNALERROR;break;
2129   }
2130 }
2131
2132 GSM_Error N6110_DeleteCalendarNote(GSM_CalendarNote *CalendarNote)
2133 {
2134
2135   unsigned char req[] = { N6110_FRAME_HEADER,
2136                           0x68, 0x00
2137                         };
2138
2139   req[4]=CalendarNote->Location;
2140
2141   return NULL_SendMessageSequence (20, &CurrentCalendarNoteError, 5, 0x13, req);
2142 }
2143
2144 void N6110_ReplyRFBatteryLevel(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2145
2146 #ifdef DEBUG
2147     fprintf(stdout, _("Message: Phone status received:\n"));
2148     fprintf(stdout, _("   Mode: "));
2149
2150     switch (MessageBuffer[4]) {
2151
2152       case 0x01:
2153
2154         fprintf(stdout, _("registered within the network\n"));
2155         break;
2156               
2157       /* I was really amazing why is there a hole in the type of 0x02, now I
2158          know... */
2159       case 0x02: fprintf(stdout, _("call in progress\n"));          break; /* ringing or already answered call */
2160       case 0x03: fprintf(stdout, _("waiting for security code\n")); break;
2161       case 0x04: fprintf(stdout, _("powered off\n"));               break;
2162       default  : fprintf(stdout, _("unknown\n"));
2163
2164     }
2165
2166     fprintf(stdout, _("   Power source: "));
2167
2168     switch (MessageBuffer[7]) {
2169
2170       case 0x01: fprintf(stdout, _("AC/DC\n"));   break;
2171       case 0x02: fprintf(stdout, _("battery\n")); break;
2172       default  : fprintf(stdout, _("unknown\n"));
2173
2174     }
2175
2176     fprintf(stdout, _("   Battery Level: %d\n"), MessageBuffer[8]);
2177     fprintf(stdout, _("   Signal strength: %d\n"), MessageBuffer[5]);
2178 #endif /* DEBUG */
2179
2180     CurrentRFLevel=MessageBuffer[5];
2181     CurrentBatteryLevel=MessageBuffer[8];
2182     CurrentPowerSource=MessageBuffer[7];
2183 }
2184
2185
2186 GSM_Error N6110_GetRFLevel(GSM_RFUnits *units, float *level)
2187 {
2188
2189   /* FIXME - these values are from 3810 code, may be incorrect.  Map from
2190      values returned in status packet to the the values returned by the AT+CSQ
2191      command. */
2192   float csq_map[5] = {0, 8, 16, 24, 31};
2193
2194   int timeout=10;
2195   int rf_level;
2196   
2197   char screen[NM_MAX_SCREEN_WIDTH];
2198
2199   CurrentRFLevel=-1;
2200     
2201   if (GetModelFeature (FN_NOPOWERFRAME)==F_NOPOWER) {
2202
2203     if (N6110_NetMonitor(1, screen)!=GE_NONE)
2204       return GE_INTERNALERROR;
2205     
2206     rf_level=4;
2207     
2208     if (screen[4]!='-') {
2209       if (screen[5]=='9' && screen[6]>'4') rf_level=1;
2210       if (screen[5]=='9' && screen[6]<'5') rf_level=2;
2211       if (screen[5]=='8' && screen[6]>'4') rf_level=3;      
2212     } else rf_level=0;
2213
2214     /* Arbitrary units. */
2215     if (*units == GRF_Arbitrary) {
2216       *level = rf_level;
2217       return (GE_NONE);
2218     }
2219     
2220   } else {
2221     N6110_SendStatusRequest();
2222
2223     /* Wait for timeout or other error. */
2224     while (timeout != 0 && CurrentRFLevel == -1 ) {
2225
2226       if (--timeout == 0)
2227         return (GE_TIMEOUT);
2228
2229       usleep (100000);
2230     }
2231
2232     /* Make copy in case it changes. */
2233     rf_level = CurrentRFLevel;
2234
2235     if (rf_level == -1)
2236       return (GE_NOLINK);
2237
2238     /* Now convert between the different units we support. */
2239
2240     /* Arbitrary units. */
2241     if (*units == GRF_Arbitrary) {
2242       *level = rf_level;
2243       return (GE_NONE);
2244     }
2245
2246     /* CSQ units. */
2247     if (*units == GRF_CSQ) {
2248
2249       if (rf_level <=4)
2250         *level = csq_map[rf_level];
2251       else
2252         *level = 99; /* Unknown/undefined */
2253
2254       return (GE_NONE);
2255     }
2256   }
2257
2258   /* Unit type is one we don't handle so return error */
2259   return (GE_INTERNALERROR);
2260 }
2261
2262
2263 GSM_Error N6110_GetBatteryLevel(GSM_BatteryUnits *units, float *level)
2264 {
2265   int timeout=10;
2266   int batt_level;
2267
2268   char screen[NM_MAX_SCREEN_WIDTH];
2269
2270   CurrentBatteryLevel=-1;
2271
2272   if (GetModelFeature (FN_NOPOWERFRAME)==F_NOPOWER) {
2273
2274     if (N6110_NetMonitor(23, screen)!=GE_NONE)
2275       return GE_NOLINK;
2276     
2277     batt_level=4;
2278     
2279     if (screen[29]=='7') batt_level=3;
2280     if (screen[29]=='5') batt_level=2;
2281     if (screen[29]=='2') batt_level=1;
2282     
2283     /* Only units we handle at present are GBU_Arbitrary */
2284     if (*units == GBU_Arbitrary) {
2285       *level = batt_level;
2286       return (GE_NONE);
2287     }
2288
2289     return (GE_INTERNALERROR);    
2290     
2291   } else {
2292     N6110_SendStatusRequest();
2293
2294     /* Wait for timeout or other error. */
2295     while (timeout != 0 && CurrentBatteryLevel == -1 ) {
2296
2297       if (--timeout == 0)
2298         return (GE_TIMEOUT);
2299
2300       usleep (100000);
2301     }
2302
2303     /* Take copy in case it changes. */
2304     batt_level = CurrentBatteryLevel;
2305
2306     if (batt_level != -1) {
2307
2308       /* Only units we handle at present are GBU_Arbitrary */
2309       if (*units == GBU_Arbitrary) {
2310         *level = batt_level;
2311         return (GE_NONE);
2312       }
2313
2314       return (GE_INTERNALERROR);
2315     }
2316     else
2317       return (GE_NOLINK);
2318   }
2319 }
2320
2321 GSM_Error N6110_GetPowerSource(GSM_PowerSource *source)
2322 {
2323
2324   int timeout=10;
2325
2326   char screen[NM_MAX_SCREEN_WIDTH];
2327
2328   CurrentPowerSource=-1;
2329
2330   if (GetModelFeature (FN_NOPOWERFRAME)==F_NOPOWER) {    
2331
2332     if (N6110_NetMonitor(20, screen)!=GE_NONE)
2333       return GE_NOLINK;
2334     
2335     CurrentPowerSource=GPS_ACDC;
2336
2337     if (screen[6]=='x') CurrentPowerSource=GPS_BATTERY;
2338
2339     *source=CurrentPowerSource;        
2340     
2341     return GE_NONE;    
2342   } else {
2343     N6110_SendStatusRequest();
2344
2345     /* Wait for timeout or other error. */
2346     while (timeout != 0 && CurrentPowerSource == -1 ) {
2347
2348       if (--timeout == 0)
2349         return (GE_TIMEOUT);
2350
2351       usleep (100000);
2352     }
2353
2354     if (CurrentPowerSource != -1) {
2355       *source=CurrentPowerSource;
2356       return (GE_NONE);
2357     }
2358     else
2359       return (GE_NOLINK);
2360   }
2361 }
2362
2363 void N6110_ReplyGetDisplayStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2364
2365   int i;
2366
2367   for (i=0; i<MessageBuffer[4];i++)
2368     if (MessageBuffer[2*i+6]==2)
2369       CurrentDisplayStatus|=1<<(MessageBuffer[2*i+5]-1);
2370     else
2371       CurrentDisplayStatus&= (0xff - (1<<(MessageBuffer[2*i+5]-1)));
2372
2373 #ifdef DEBUG
2374   fprintf(stdout, _("Call in progress: %s\n"), CurrentDisplayStatus & (1<<DS_Call_In_Progress)?"on":"off");
2375   fprintf(stdout, _("Unknown: %s\n"),          CurrentDisplayStatus & (1<<DS_Unknown)?"on":"off");
2376   fprintf(stdout, _("Unread SMS: %s\n"),       CurrentDisplayStatus & (1<<DS_Unread_SMS)?"on":"off");
2377   fprintf(stdout, _("Voice call: %s\n"),       CurrentDisplayStatus & (1<<DS_Voice_Call)?"on":"off");
2378   fprintf(stdout, _("Fax call active: %s\n"),  CurrentDisplayStatus & (1<<DS_Fax_Call)?"on":"off");
2379   fprintf(stdout, _("Data call active: %s\n"), CurrentDisplayStatus & (1<<DS_Data_Call)?"on":"off");
2380   fprintf(stdout, _("Keyboard lock: %s\n"),    CurrentDisplayStatus & (1<<DS_Keyboard_Lock)?"on":"off");
2381   fprintf(stdout, _("SMS storage full: %s\n"), CurrentDisplayStatus & (1<<DS_SMS_Storage_Full)?"on":"off");
2382 #endif /* DEBUG */
2383
2384   CurrentDisplayStatusError=GE_NONE;
2385 }
2386
2387 GSM_Error N6110_GetDisplayStatus(int *Status) {
2388
2389   unsigned char req[4]={ N6110_FRAME_HEADER, 0x51 };
2390
2391   GSM_Error error;
2392
2393   error=NULL_SendMessageSequence
2394     (10, &CurrentDisplayStatusError, 4, 0x0d, req);
2395   if (error!=GE_NONE) return error;
2396   
2397   *Status=CurrentDisplayStatus;
2398
2399   return GE_NONE;
2400 }
2401
2402 GSM_Error N6110_DialVoice(char *Number) {
2403 /* This commented sequence doesn't work on N3210/3310/6210/7110 */
2404 //  unsigned char req[64]={N6110_FRAME_HEADER, 0x01};
2405 //  unsigned char req_end[]={0x05, 0x01, 0x01, 0x05, 0x81, 0x01, 0x00, 0x00, 0x01};
2406 //  int i=0;
2407 //  req[4]=strlen(Number);
2408 //  for(i=0; i < strlen(Number) ; i++)
2409 //   req[5+i]=Number[i];
2410 //  memcpy(req+5+strlen(Number), req_end, 10);
2411 //  return NULL_SendMessageSequence
2412 //    (20, &CurrentDialVoiceError, 13+strlen(Number), 0x01, req);
2413
2414   unsigned char req[64]={0x00,0x01,0x7c,
2415                          0x01}; //call command
2416
2417   int i=0;                       
2418   
2419   GSM_Error error;
2420
2421   error=N6110_EnableExtendedCommands(0x01);
2422   if (error!=GE_NONE) return error;
2423
2424   for(i=0; i < strlen(Number) ; i++) req[4+i]=Number[i];
2425   
2426   req[4+i+1]=0;
2427   
2428   return NULL_SendMessageSequence
2429     (20, &CurrentDialVoiceError, 4+strlen(Number)+1, 0x40, req);  
2430 }
2431
2432 /* Dial a data call - type specifies request to use: 
2433      type 0 should normally be used
2434      type 1 should be used when calling a digital line - corresponds to ats35=0
2435      Maybe one day we'll know what they mean!
2436 */
2437 GSM_Error N6110_DialData(char *Number, char type, void (* callpassup)(char c))
2438 {
2439         unsigned char req[100]   = { N6110_FRAME_HEADER, 0x01 };
2440         unsigned char *req_end;
2441         unsigned char req_end0[] = { 0x01,  /* make a data call = type 0x01 */
2442                                      0x02,0x01,0x05,0x81,0x01,0x00,0x00,0x01,0x02,0x0a,
2443                                      0x07,0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00 };
2444         unsigned char req_end1[] = { 0x01,
2445                                      0x02,0x01,0x05,0x81,0x01,0x00,0x00,0x01,0x02,0x0a,
2446                                      0x07,0xa1,0x88,0x89,0x21,0x15,0x63,0xa0,0x00,0x06,
2447                                      0x88,0x90,0x21,0x48,0x40,0xbb };
2448         unsigned char req2[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x01,
2449                                      0x07,0xa2,0xc8,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
2450                                      0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80,0x01,0x60 };
2451         unsigned char req3[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x01,
2452                                      0x07,0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
2453                                      0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80 };
2454         unsigned char req4[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x81,
2455                                      0x07,0xa1,0x88,0x89,0x21,0x15,0x63,0xa0,0x00,0x06,
2456                                      0x88,0x90,0x21,0x48,0x40,0xbb,0x07,0xa3,0xb8,0x81,
2457                                      0x20,0x15,0x63,0x80 };
2458
2459         int i = 0;
2460         u8 size;
2461
2462         CurrentCallPassup=callpassup;
2463
2464         switch (type) {
2465         case 0:
2466                 req_end = req_end0;
2467                 size = sizeof(req_end0);
2468                 break;
2469         case 1:
2470                 Protocol->SendMessage(sizeof(req3), 0x01, req3);
2471                 Protocol->SendMessage(sizeof(req4), 0x01, req4);
2472                 req_end = req_end1;
2473                 size = sizeof(req_end1);
2474                 break;
2475         case -1:   /* Just used to set the call passup */
2476                 return GE_NONE;
2477                 break;
2478         default:
2479                 req_end = req_end0;
2480                 size = sizeof(req_end0);
2481                 break;
2482         }
2483
2484         req[4] = strlen(Number);
2485
2486         for(i = 0; i < strlen(Number) ; i++)
2487                 req[5+i] = Number[i];
2488
2489         memcpy(req + 5 + strlen(Number), req_end, size);
2490
2491         Protocol->SendMessage(5 + size + strlen(Number), 0x01, req);
2492         if (type != 1) Protocol->SendMessage(26, 0x01, req2);
2493
2494         return (GE_NONE);
2495 }
2496
2497 GSM_Error N6110_GetIncomingCallNr(char *Number)
2498 {
2499
2500   if (*CurrentIncomingCall != ' ') {
2501     strcpy(Number, CurrentIncomingCall);
2502     return GE_NONE;
2503   }
2504   else
2505     return GE_BUSY;
2506 }
2507
2508 GSM_Error N6110_CancelCall(void)
2509 {
2510 //  This frame & method works only on 61xx/51xx
2511 //  unsigned char req[] = { N6110_FRAME_HEADER, 0x08, 0x00, 0x85};
2512 //  req[4]=CurrentCallSequenceNumber;
2513 //  Protocol->SendMessage(6, 0x01, req);
2514 //  return GE_NONE;
2515  
2516   GSM_Error error;
2517
2518   unsigned char req[]={0x00,0x01,0x7c,0x03};
2519     
2520   /* Checking */
2521   error=N6110_EnableExtendedCommands(0x01);
2522   if (error!=GE_NONE) return error;
2523
2524   return NULL_SendMessageSequence (20, &CurrentDialVoiceError, 4, 0x40, req);   
2525 }  
2526
2527 void N6110_ReplyEnterSecurityCode(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2528     
2529   switch(MessageBuffer[3]) {
2530
2531   case 0x0b:
2532 #ifdef DEBUG
2533     fprintf(stdout, _("Message: Security code accepted.\n"));
2534 #endif /* DEBUG */
2535     CurrentSecurityCodeError = GE_NONE;
2536     break;
2537
2538   default:
2539 #ifdef DEBUG
2540     fprintf(stdout, _("Message: Security code is wrong. You're not my big owner :-)\n"));
2541 #endif /* DEBUG */
2542     CurrentSecurityCodeError = GE_INVALIDSECURITYCODE;
2543   }
2544 }
2545
2546 GSM_Error N6110_EnterSecurityCode(GSM_SecurityCode SecurityCode)
2547 {
2548
2549   unsigned char req[15] = { N6110_FRAME_HEADER,
2550                             0x0a, /* Enter code request. */
2551                             0x00  /* Type of the entered code. */
2552                             };
2553   int i=0;
2554
2555   req[4]=SecurityCode.Type;
2556
2557   for (i=0; i<strlen(SecurityCode.Code);i++)
2558     req[5+i]=SecurityCode.Code[i];
2559
2560   req[5+strlen(SecurityCode.Code)]=0x00;
2561   req[6+strlen(SecurityCode.Code)]=0x00;
2562
2563   return NULL_SendMessageSequence
2564     (20, &CurrentSecurityCodeError, 7+strlen(SecurityCode.Code), 0x08, req);
2565 }
2566
2567 void N6110_ReplyGetSecurityCodeStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2568     
2569   *CurrentSecurityCodeStatus = MessageBuffer[4];
2570
2571 #ifdef DEBUG
2572   fprintf(stdout, _("Message: Security Code status received: "));
2573
2574   switch(*CurrentSecurityCodeStatus) {
2575
2576     case GSCT_SecurityCode: fprintf(stdout, _("waiting for Security Code.\n")); break;
2577     case GSCT_Pin         : fprintf(stdout, _("waiting for PIN.\n")); break;
2578     case GSCT_Pin2        : fprintf(stdout, _("waiting for PIN2.\n")); break;
2579     case GSCT_Puk         : fprintf(stdout, _("waiting for PUK.\n")); break;
2580     case GSCT_Puk2        : fprintf(stdout, _("waiting for PUK2.\n")); break;
2581     case GSCT_None        : fprintf(stdout, _("nothing to enter.\n")); break;
2582     default               : fprintf(stdout, _("Unknown!\n"));
2583   }
2584       
2585 #endif /* DEBUG */
2586
2587   CurrentSecurityCodeError = GE_NONE;
2588 }
2589
2590 GSM_Error N6110_GetSecurityCodeStatus(int *Status)
2591 {
2592
2593   unsigned char req[4] = { N6110_FRAME_HEADER,
2594                            0x07
2595                          };
2596
2597   CurrentSecurityCodeStatus=Status;
2598
2599   return NULL_SendMessageSequence
2600     (20, &CurrentSecurityCodeError, 4, 0x08, req);
2601 }
2602
2603 void N6110_ReplyGetSecurityCode(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2604
2605   int i;
2606   
2607 #ifdef DEBUG
2608   fprintf(stdout, _("Message: Security code received: "));
2609   switch (MessageBuffer[3]) {
2610     case GSCT_SecurityCode: fprintf(stdout, _("Security code"));break;
2611     case GSCT_Pin:  fprintf(stdout, _("PIN"));break;
2612     case GSCT_Pin2: fprintf(stdout, _("PIN2"));break;
2613     case GSCT_Puk:  fprintf(stdout, _("PUK"));break;
2614     case GSCT_Puk2: fprintf(stdout, _("PUK2"));break;
2615     default: fprintf(stdout, _("unknown !"));break;
2616   }
2617   if (MessageBuffer[4]==1) {
2618     fprintf(stdout, _(" allowed, value \""));
2619     if (MessageBuffer[3]==GSCT_SecurityCode) {
2620       for (i=0;i<5;i++) {fprintf(stdout, _("%c"), MessageBuffer[5+i]);}
2621     }
2622     if (MessageBuffer[3]==GSCT_Pin || MessageBuffer[3]==GSCT_Pin2 ||
2623         MessageBuffer[3]==GSCT_Puk || MessageBuffer[3]==GSCT_Puk2) {
2624       for (i=0;i<4;i++) {fprintf(stdout, _("%c"), MessageBuffer[5+i]);}
2625     }
2626     fprintf(stdout, _("\""));
2627   } else {
2628     fprintf(stdout, _(" not allowed"));  
2629   }
2630   fprintf(stdout, _("\n"));  
2631 #endif /* DEBUG */
2632       
2633   if (CurrentSecurityCode->Type==MessageBuffer[3] /* We wanted this code */
2634           && MessageBuffer[4]==1) {                      /* It's allowed */
2635     if (MessageBuffer[3]==GSCT_SecurityCode) {
2636       for (i=0;i<5;i++) {CurrentSecurityCode->Code[i]=MessageBuffer[5+i];}
2637       CurrentSecurityCode->Code[5]=0;
2638     }
2639     if (MessageBuffer[3]==GSCT_Pin || MessageBuffer[3]==GSCT_Pin2 ||
2640         MessageBuffer[3]==GSCT_Puk || MessageBuffer[3]==GSCT_Puk2) {
2641       for (i=0;i<4;i++) {CurrentSecurityCode->Code[i]=MessageBuffer[5+i];}
2642       CurrentSecurityCode->Code[4]=0;
2643     }
2644     CurrentSecurityCodeError=GE_NONE;
2645   } else
2646     CurrentSecurityCodeError=GE_INVALIDSECURITYCODE;
2647 }
2648
2649 GSM_Error N6110_GetSecurityCode(GSM_SecurityCode *SecurityCode)
2650 {
2651
2652   unsigned char req[4] = { 0x00,
2653                            0x01,0x6e, /* Get code request. */
2654                            0x00 };    /* Type of the requested code. */
2655
2656   GSM_Error error;
2657   
2658   error=N6110_EnableExtendedCommands(0x01);
2659   if (error!=GE_NONE) return error;
2660   
2661   req[3]=SecurityCode->Type;
2662
2663   CurrentSecurityCode=SecurityCode;
2664
2665   return NULL_SendMessageSequence
2666     (20, &CurrentSecurityCodeError, 4, 0x40, req);
2667 }
2668
2669 void N6110_ReplyPlayTone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2670
2671 #ifdef DEBUG
2672   fprintf(stdout, _("Message: answer for PlayTone frame\n"));      
2673 #endif
2674       
2675   CurrentPlayToneError=GE_NONE;      
2676 }
2677
2678 GSM_Error N6110_PlayTone(int Herz, u8 Volume)
2679 {
2680   unsigned char req[6] = { 0x00,0x01,0x8f,
2681                            0x00,   /* Volume */
2682                            0x00,   /* HerzLo */
2683                            0x00 }; /* HerzHi */
2684
2685   GSM_Error error;
2686
2687   /* PlayTone wasn't used earlier */
2688   if (CurrentPlayToneError==GE_UNKNOWN) {
2689     if (CurrentConnectionType!=GCT_MBUS)
2690       CurrentDisableKeepAlive=true;
2691
2692     error=N6110_EnableExtendedCommands(0x01);
2693     if (error!=GE_NONE) return error;
2694   }
2695
2696   /* For Herz==255*255 we have silent */  
2697   if (Herz!=255*255) {
2698     req[3]=Volume;
2699
2700     req[5]=Herz%256;
2701     req[4]=Herz/256;
2702   } else {
2703     req[3]=0;
2704
2705     req[5]=0;
2706     req[4]=0;
2707   }
2708
2709 #ifdef WIN32
2710   /* For Herz==255*255 we have silent and additionaly
2711      we wait for phone answer - it's important for MBUS */
2712   if (Herz==255*255) {
2713     error=NULL_SendMessageSequence
2714       (20, &CurrentPlayToneError, 6, 0x40, req);
2715
2716     CurrentPlayToneError=GE_UNKNOWN;
2717     CurrentDisableKeepAlive=false;
2718
2719     if (error!=GE_NONE) return error;
2720   } else {
2721     Protocol->SendMessage(6,0x40,req);
2722   }
2723 #else
2724   error=NULL_SendMessageSequence
2725     (20, &CurrentPlayToneError, 6, 0x40, req);
2726
2727   /* For Herz==255*255 we wait for phone answer - it's important for MBUS */
2728   if (Herz==255*255) {
2729     CurrentPlayToneError=GE_UNKNOWN;
2730     CurrentDisableKeepAlive=false;
2731   }
2732   
2733   if (error!=GE_NONE) return error;
2734
2735 #endif
2736     
2737   return(GE_NONE);
2738 }
2739
2740 void N6110_ReplyGetDateTime(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2741
2742   if (MessageBuffer[4]==0x01) {
2743     DecodeDateTime(MessageBuffer+8, CurrentDateTime);
2744
2745 #ifdef DEBUG
2746     fprintf(stdout, _("Message: Date and time\n"));
2747     fprintf(stdout, _("   Time: %02d:%02d:%02d\n"), CurrentDateTime->Hour, CurrentDateTime->Minute, CurrentDateTime->Second);
2748     fprintf(stdout, _("   Date: %4d/%02d/%02d\n"), CurrentDateTime->Year, CurrentDateTime->Month, CurrentDateTime->Day);
2749 #endif /* DEBUG */
2750
2751     CurrentDateTime->IsSet=true;
2752   } else {
2753
2754 #ifdef DEBUG
2755     fprintf(stdout, _("Message: Date and time not set in phone\n"));
2756 #endif
2757
2758     CurrentDateTime->IsSet=false;
2759   }
2760       
2761   CurrentDateTimeError=GE_NONE;
2762 }
2763
2764 GSM_Error N6110_GetDateTime(GSM_DateTime *date_time)
2765 {
2766   return N6110_PrivGetDateTime(date_time,0x11);
2767 }
2768
2769 GSM_Error N6110_PrivGetDateTime(GSM_DateTime *date_time, int msgtype)
2770 {
2771   unsigned char req[] = {N6110_FRAME_HEADER, 0x62};
2772
2773   CurrentDateTime=date_time;
2774
2775   return NULL_SendMessageSequence
2776     (50, &CurrentDateTimeError, 4, msgtype, req);
2777 }
2778
2779 void N6110_ReplyGetAlarm(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2780
2781 #ifdef DEBUG
2782   fprintf(stdout, _("Message: Alarm\n"));
2783   fprintf(stdout, _("   Alarm: %02d:%02d\n"), MessageBuffer[9], MessageBuffer[10]);
2784   fprintf(stdout, _("   Alarm is %s\n"), (MessageBuffer[8]==2) ? _("on"):_("off"));
2785 #endif /* DEBUG */
2786
2787   CurrentAlarm->Hour=MessageBuffer[9];
2788   CurrentAlarm->Minute=MessageBuffer[10];
2789   CurrentAlarm->Second=0;
2790
2791   CurrentAlarm->IsSet=(MessageBuffer[8]==2);
2792
2793   CurrentAlarmError=GE_NONE;
2794 }
2795
2796 GSM_Error N6110_GetAlarm(int alarm_number, GSM_DateTime *date_time)
2797 {
2798   return N6110_PrivGetAlarm(alarm_number,date_time,0x11);
2799 }
2800
2801 GSM_Error N6110_PrivGetAlarm(int alarm_number, GSM_DateTime *date_time, int msgtype)
2802 {
2803   unsigned char req[] = {N6110_FRAME_HEADER, 0x6d};
2804
2805   CurrentAlarm=date_time;
2806
2807   return NULL_SendMessageSequence
2808     (50, &CurrentAlarmError, 4, msgtype, req);
2809 }
2810
2811 void N6110_ReplyGetSMSCenter(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2812   
2813   switch (MessageBuffer[3]) {
2814
2815   case 0x34:
2816
2817     CurrentMessageCenter->No=MessageBuffer[4];
2818     CurrentMessageCenter->Format=MessageBuffer[6];
2819     CurrentMessageCenter->Validity=MessageBuffer[8];
2820     sprintf(CurrentMessageCenter->Name, "%s", MessageBuffer+33);
2821
2822     sprintf(CurrentMessageCenter->DefaultRecipient, "%s", GSM_UnpackSemiOctetNumber(MessageBuffer+9,false));
2823
2824     sprintf(CurrentMessageCenter->Number, "%s", GSM_UnpackSemiOctetNumber(MessageBuffer+21,false));
2825       
2826 #ifdef DEBUG
2827     fprintf(stdout, _("Message: SMS Center received:\n"));
2828     fprintf(stdout, _("   %d. SMS Center name is %s\n"), CurrentMessageCenter->No, CurrentMessageCenter->Name);
2829     fprintf(stdout, _("   SMS Center number is %s\n"), CurrentMessageCenter->Number);
2830     fprintf(stdout, _("   Default recipient number is %s\n"), CurrentMessageCenter->DefaultRecipient);
2831       
2832     fprintf(stdout, _("   SMS Center message format is "));
2833
2834     switch (CurrentMessageCenter->Format) {
2835
2836       case GSMF_Text  : fprintf(stdout, _("Text"));   break;
2837       case GSMF_Paging: fprintf(stdout, _("Paging")); break;
2838       case GSMF_Fax   : fprintf(stdout, _("Fax"));    break;
2839       case GSMF_Email : fprintf(stdout, _("Email"));  break;
2840       default         : fprintf(stdout, _("Unknown"));
2841     }
2842
2843     fprintf(stdout, "\n");
2844
2845     fprintf(stdout, _("   SMS Center message validity is "));
2846
2847     switch (CurrentMessageCenter->Validity) {
2848
2849       case GSMV_1_Hour  : fprintf(stdout, _("1 hour"));      break;
2850       case GSMV_6_Hours : fprintf(stdout, _("6 hours"));     break;
2851       case GSMV_24_Hours: fprintf(stdout, _("24 hours"));    break;
2852       case GSMV_72_Hours: fprintf(stdout, _("72 hours"));    break;
2853       case GSMV_1_Week  : fprintf(stdout, _("1 week"));      break;
2854       case GSMV_Max_Time: fprintf(stdout, _("Maximum time"));break;
2855       default           : fprintf(stdout, _("Unknown"));
2856     }
2857
2858     fprintf(stdout, "\n");
2859
2860 #endif /* DEBUG */
2861
2862     CurrentMessageCenterError=GE_NONE;
2863
2864     break;
2865
2866   case 0x35:
2867
2868     /* Number of entries depends on SIM card */
2869
2870 #ifdef DEBUG
2871     fprintf(stdout, _("Message: SMS Center error received:\n"));
2872     fprintf(stdout, _("   The request for SMS Center failed.\n"));
2873 #endif /* DEBUG */
2874
2875     /* FIXME: appropriate error. */
2876     CurrentMessageCenterError=GE_INTERNALERROR;
2877
2878     break;  
2879
2880   }
2881 }
2882
2883 /* This function sends to the mobile phone a request for the SMS Center */
2884 GSM_Error N6110_GetSMSCenter(GSM_MessageCenter *MessageCenter)
2885 {
2886   unsigned char req[] = { N6110_FRAME_HEADER, 0x33, 0x64,
2887                           0x00 /* SMS Center Number. */
2888                         };
2889
2890   req[5]=MessageCenter->No;
2891
2892   CurrentMessageCenter=MessageCenter;
2893
2894   return NULL_SendMessageSequence
2895     (50, &CurrentMessageCenterError, 6, 0x02, req);
2896 }
2897
2898 void N6110_ReplySetSMSCenter(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2899
2900 #ifdef DEBUG
2901   fprintf(stdout, _("Message: SMS Center correctly set.\n"));
2902 #endif
2903   CurrentMessageCenterError=GE_NONE;
2904 }
2905
2906 /* This function set the SMS Center profile on the phone. */
2907 GSM_Error N6110_SetSMSCenter(GSM_MessageCenter *MessageCenter)
2908 {
2909   unsigned char req[64] = { N6110_FRAME_HEADER, 0x30, 0x64,
2910                             0x00, /* SMS Center Number. */
2911                             0x00, /* Unknown. */
2912                             0x00, /* SMS Message Format. */
2913                             0x00, /* Unknown. */
2914                             0x00, /* Validity. */
2915                             0,0,0,0,0,0,0,0,0,0,0,0, /* Default recipient number */
2916                             0,0,0,0,0,0,0,0,0,0,0,0 /* Message Center Number. */
2917                             /* Message Center Name. */
2918                           };
2919
2920   req[5]=MessageCenter->No;
2921   req[7]=MessageCenter->Format;
2922   req[9]=MessageCenter->Validity;
2923
2924   req[10]=GSM_PackSemiOctetNumber(MessageCenter->DefaultRecipient, req+11, false);
2925
2926   req[22]=GSM_PackSemiOctetNumber(MessageCenter->Number, req+23, false);
2927
2928   sprintf(req+34, "%s", MessageCenter->Name);
2929
2930   CurrentMessageCenter=MessageCenter;
2931
2932   return NULL_SendMessageSequence
2933     (50, &CurrentMessageCenterError, 35+strlen(MessageCenter->Name), 0x02, req);
2934 }
2935
2936 void N6110_ReplyGetSMSStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2937
2938   switch (MessageBuffer[3]) {
2939
2940   case 0x37:
2941
2942 #ifdef DEBUG
2943     fprintf(stdout, _("Message: SMS Status Received\n"));
2944     fprintf(stdout, _("   The number of messages: %d\n"), MessageBuffer[10]);
2945     fprintf(stdout, _("   Unread messages: %d\n"), MessageBuffer[11]);
2946 #endif /* DEBUG */
2947
2948     CurrentSMSStatus->UnRead = MessageBuffer[11];
2949     CurrentSMSStatus->Number = MessageBuffer[10];
2950     
2951     CurrentSMSStatusError = GE_NONE;
2952     break;
2953
2954   case 0x38:
2955
2956 #ifdef DEBUG
2957     fprintf(stdout, _("Message: SMS Status error, probably not authorized by PIN\n"));
2958 #endif /* DEBUG */
2959
2960     CurrentSMSStatusError = GE_INTERNALERROR;
2961     break;
2962           
2963   }
2964 }
2965
2966 GSM_Error N6110_GetSMSStatus(GSM_SMSStatus *Status)
2967 {
2968   unsigned char req[] = {N6110_FRAME_HEADER, 0x36, 0x64};
2969
2970   CurrentSMSStatus = Status;
2971
2972   return NULL_SendMessageSequence
2973     (10, &CurrentSMSStatusError, 5, 0x14, req);
2974 }
2975
2976 GSM_Error N6110_GetSMSFolders ( GSM_SMSFolders *folders)
2977 {
2978   folders->number=2;
2979
2980   strcpy(folders->Folder[0].Name,"Inbox");
2981   strcpy(folders->Folder[1].Name,"Outbox");
2982   
2983   return GE_NONE;
2984 }
2985
2986 GSM_Error N6110_GetIMEI(char *imei)
2987 {
2988   if (strlen(Current_IMEI)>0) {
2989     strncpy (imei, Current_IMEI, GSM_MAX_IMEI_LENGTH);
2990     return (GE_NONE);
2991   }
2992   else
2993     return (GE_TRYAGAIN);
2994 }
2995
2996 GSM_Error N6110_GetRevision(char *revision)
2997 {
2998
2999   if (strlen(Current_Revision)>0) {
3000     strncpy (revision, Current_Revision, GSM_MAX_REVISION_LENGTH);
3001     return (GE_NONE);
3002   }
3003   else
3004     return (GE_TRYAGAIN);
3005 }
3006
3007 GSM_Error N6110_GetModel(char *model)
3008 {
3009   if (strlen(Current_Model)>0) {
3010     strncpy (model, Current_Model, GSM_MAX_MODEL_LENGTH);
3011     return (GE_NONE);
3012   }
3013   else
3014     return (GE_TRYAGAIN);
3015 }
3016
3017 void N6110_ReplySetDateTime(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3018
3019   switch (MessageBuffer[4]) {
3020
3021     case 0x01:
3022 #ifdef DEBUG
3023       fprintf(stdout, _("Message: Date and time set correctly\n"));
3024 #endif /* DEBUG */
3025       CurrentSetDateTimeError=GE_NONE;
3026       break;
3027       
3028     default:
3029 #ifdef DEBUG
3030       fprintf(stdout, _("Message: Date and time setting error\n"));
3031 #endif /* DEBUG */
3032       CurrentSetDateTimeError=GE_INVALIDDATETIME;
3033
3034   }
3035 }
3036
3037 /* Needs SIM card with PIN in phone */
3038 GSM_Error N6110_SetDateTime(GSM_DateTime *date_time)
3039 {
3040   return N6110_PrivSetDateTime(date_time,0x11);
3041 }
3042
3043 /* Needs SIM card with PIN in phone */
3044 GSM_Error N6110_PrivSetDateTime(GSM_DateTime *date_time, int msgtype)
3045 {
3046
3047   unsigned char req[] = { N6110_FRAME_HEADER,
3048                           0x60, /* set-time subtype */
3049                           0x01, 0x01, 0x07, /* unknown */
3050                           0x00, 0x00, /* Year (0x07cf = 1999) */
3051                           0x00, 0x00, /* Month Day */
3052                           0x00, 0x00, /* Hours Minutes */
3053                           0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
3054                         };
3055
3056   EncodeDateTime(req+7, date_time);
3057
3058   return NULL_SendMessageSequence
3059     (20, &CurrentSetDateTimeError, 14, msgtype, req);
3060 }
3061
3062 void N6110_ReplySetAlarm(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3063
3064   switch (MessageBuffer[4]) {
3065
3066     case 0x01:
3067 #ifdef DEBUG
3068       fprintf(stdout, _("Message: Alarm set correctly\n"));
3069 #endif /* DEBUG */
3070       CurrentSetAlarmError=GE_NONE;
3071       break;
3072       
3073     default:
3074 #ifdef DEBUG
3075       fprintf(stdout, _("Message: Alarm setting error\n"));
3076 #endif /* DEBUG */
3077       CurrentSetAlarmError=GE_INVALIDDATETIME;
3078
3079   }
3080 }
3081
3082 /* FIXME: we should also allow to set the alarm off :-) */
3083 GSM_Error N6110_SetAlarm(int alarm_number, GSM_DateTime *date_time)
3084 {
3085   return N6110_PrivSetAlarm(alarm_number,date_time, 0x11);
3086 }
3087
3088 /* FIXME: we should also allow to set the alarm off :-) */
3089 GSM_Error N6110_PrivSetAlarm(int alarm_number, GSM_DateTime *date_time, int msgtype)
3090 {
3091
3092   unsigned char req[] = { N6110_FRAME_HEADER,
3093                           0x6b, /* set-alarm subtype */
3094                           0x01, 0x20, 0x03, /* unknown */
3095                           0x02,       /* should be alarm on/off, but it don't works */
3096                           0x00, 0x00, /* Hours Minutes */
3097                           0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
3098                         };
3099
3100   req[8] = date_time->Hour;
3101   req[9] = date_time->Minute;
3102
3103   return NULL_SendMessageSequence
3104     (50, &CurrentSetAlarmError, 11, msgtype, req);
3105 }
3106
3107 void N6110_ReplyGetMemoryLocation(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3108
3109   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
3110   char model[64];
3111
3112   int i, tmp, count;
3113     
3114   switch (MessageBuffer[3]) {
3115
3116   case 0x02:
3117
3118     CurrentPhonebookEntry->Empty = true;
3119
3120     count=MessageBuffer[5];
3121           
3122 #ifdef DEBUG
3123     fprintf(stdout, _("Message: Phonebook entry received:\n"));
3124     fprintf(stdout, _("   Name: "));
3125
3126     for (tmp=0; tmp <count; tmp++)
3127     {
3128       if (MessageBuffer[6+tmp]==1) fprintf(stdout, "%c", '~'); else //enables/disables blinking
3129       if (MessageBuffer[6+tmp]==0) fprintf(stdout, "%c", '`'); else //hides rest ot contents
3130       fprintf(stdout, "%c", MessageBuffer[6+tmp]);
3131     }
3132
3133     fprintf(stdout, "\n");
3134 #endif /* DEBUG */
3135
3136     while (N6110_GetModel(model)  != GE_NONE)
3137       sleep(1);
3138         
3139     if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {//pbk with Unicode
3140       DecodeUnicode (CurrentPhonebookEntry->Name, MessageBuffer+6, count/2);
3141       CurrentPhonebookEntry->Name[count/2] = 0x00;
3142     } else {
3143       memcpy(CurrentPhonebookEntry->Name, MessageBuffer + 6, count);
3144       CurrentPhonebookEntry->Name[count] = 0x00;
3145     }
3146
3147     CurrentPhonebookEntry->Empty = false;
3148
3149     for (tmp=0; tmp <count; tmp++)
3150     {
3151       if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {//pbk with Unicode
3152         /* We check only 1'st, 3'rd, ... char */
3153         if (tmp%2!=0 && MessageBuffer[6+tmp]==1) CurrentPhonebookEntry->Name[tmp/2]='~'; //enables/disables blinking
3154         if (tmp%2!=0 && MessageBuffer[6+tmp]==0) CurrentPhonebookEntry->Name[tmp/2]='`'; //hides rest ot contents
3155       } else {
3156         if (MessageBuffer[6+tmp]==1) CurrentPhonebookEntry->Name[tmp]='~'; //enables/disables blinking
3157         if (MessageBuffer[6+tmp]==0) CurrentPhonebookEntry->Name[tmp]='`'; //hides rest ot contents
3158       }
3159     }
3160
3161     i=7+count;
3162     count=MessageBuffer[6+count];
3163
3164 #ifdef DEBUG
3165     fprintf(stdout, _("   Number: "));
3166
3167     for (tmp=0; tmp <count; tmp++)
3168       fprintf(stdout, "%c", MessageBuffer[i+tmp]);
3169
3170     fprintf(stdout, "\n");
3171 #endif /* DEBUG */
3172
3173     memcpy(CurrentPhonebookEntry->Number, MessageBuffer + i, count);
3174     CurrentPhonebookEntry->Number[count] = 0x00;
3175     CurrentPhonebookEntry->Group = MessageBuffer[i+count];
3176       
3177     /* Phone doesn't have entended phonebook */
3178     CurrentPhonebookEntry->SubEntriesCount = 0;
3179
3180     /* But for these memories data is saved and we can save it using 7110/6210 style */
3181     if (CurrentPhonebookEntry->MemoryType==GMT_DC ||
3182         CurrentPhonebookEntry->MemoryType==GMT_RC ||
3183         CurrentPhonebookEntry->MemoryType==GMT_MC) {
3184         CurrentPhonebookEntry->SubEntriesCount = 1;
3185         CurrentPhonebookEntry->SubEntries[0].EntryType=N7110_ENTRYTYPE_DATE;
3186         CurrentPhonebookEntry->SubEntries[0].NumberType=0;
3187         CurrentPhonebookEntry->SubEntries[0].BlockNumber=1;
3188         DecodeDateTime(MessageBuffer+(i+count+2),&CurrentPhonebookEntry->SubEntries[0].data.Date);
3189
3190 #ifdef DEBUG
3191       fprintf(stdout, _("   Date: "));
3192       fprintf(stdout, "%02u.%02u.%04u\n",
3193           CurrentPhonebookEntry->SubEntries[0].data.Date.Day,
3194           CurrentPhonebookEntry->SubEntries[0].data.Date.Month,
3195           CurrentPhonebookEntry->SubEntries[0].data.Date.Year);
3196       fprintf(stdout, _("   Time: "));
3197       fprintf(stdout, "%02u:%02u:%02u\n",
3198           CurrentPhonebookEntry->SubEntries[0].data.Date.Hour,
3199           CurrentPhonebookEntry->SubEntries[0].data.Date.Minute,
3200           CurrentPhonebookEntry->SubEntries[0].data.Date.Second);
3201 #endif /* DEBUG */
3202
3203       /* These values are set, when date and time unavailable in phone.
3204          Values from 3310 - in other can be different */
3205       if (CurrentPhonebookEntry->SubEntries[0].data.Date.Day==20 &&
3206           CurrentPhonebookEntry->SubEntries[0].data.Date.Month==1 &&
3207           CurrentPhonebookEntry->SubEntries[0].data.Date.Year==2118 &&
3208           CurrentPhonebookEntry->SubEntries[0].data.Date.Hour==3 &&
3209           CurrentPhonebookEntry->SubEntries[0].data.Date.Minute==14 &&
3210           CurrentPhonebookEntry->SubEntries[0].data.Date.Second==7)
3211           CurrentPhonebookEntry->SubEntriesCount = 0;
3212     }
3213
3214     /* Signal no error to calling code. */
3215     CurrentPhonebookError = GE_NONE;
3216
3217     break;
3218
3219   case 0x03:
3220
3221 #ifdef DEBUG
3222     fprintf(stdout, _("Message: Phonebook read entry error received:\n"));
3223 #endif /* DEBUG */
3224
3225     switch (MessageBuffer[4]) {
3226
3227       case 0x7d:
3228 #ifdef DEBUG
3229         fprintf(stdout, _("   Invalid memory type!\n"));
3230 #endif /* DEBUG */
3231         CurrentPhonebookError = GE_INVALIDMEMORYTYPE;
3232         break;
3233
3234       default:
3235 #ifdef DEBUG
3236         fprintf(stdout, _("   Unknown error!\n"));
3237 #endif /* DEBUG */
3238         CurrentPhonebookError = GE_INTERNALERROR;
3239     }
3240
3241     break;
3242
3243   }
3244 }
3245
3246 /* Routine to get specifed phone book location.  Designed to be called by
3247    application.  Will block until location is retrieved or a timeout/error
3248    occurs. */
3249 GSM_Error N6110_GetMemoryLocation(GSM_PhonebookEntry *entry)
3250 {
3251   unsigned char req[] = {N6110_FRAME_HEADER, 0x01, 0x00, 0x00, 0x00};
3252
3253   CurrentPhonebookEntry = entry;
3254
3255   req[4] = N6110_GetMemoryType(entry->MemoryType);
3256   req[5] = entry->Location;
3257
3258   return NULL_SendMessageSequence
3259     (50, &CurrentPhonebookError, 7, 0x03, req);
3260 }
3261
3262 void N6110_ReplyWritePhonebookLocation(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3263
3264   switch (MessageBuffer[3]) {
3265
3266   case 0x05:
3267
3268 #ifdef DEBUG
3269     fprintf(stdout, _("Message: Phonebook written correctly.\n"));
3270 #endif /* DEBUG */
3271     CurrentPhonebookError = GE_NONE;
3272     break;
3273
3274   case 0x06:
3275
3276     switch (MessageBuffer[4]) {
3277       /* FIXME: other errors? When I send the phonebook with index of 350 it
3278          still report error 0x7d :-( */
3279       case 0x7d:
3280 #ifdef DEBUG
3281         fprintf(stdout, _("Message: Phonebook not written - name is too long.\n"));
3282 #endif /* DEBUG */
3283         CurrentPhonebookError = GE_PHBOOKNAMETOOLONG;
3284         break;
3285
3286       default:
3287 #ifdef DEBUG
3288         fprintf(stdout, _("   Unknown error!\n"));
3289 #endif /* DEBUG */
3290         CurrentPhonebookError = GE_INTERNALERROR;
3291     }
3292   }
3293 }
3294
3295 /* Routine to write phonebook location in phone. Designed to be called by
3296    application code. Will block until location is written or timeout
3297    occurs. */
3298 GSM_Error N6110_WritePhonebookLocation(GSM_PhonebookEntry *entry)
3299 {
3300   unsigned char req[128] = { N6110_FRAME_HEADER, 0x04, 0x00, 0x00 };
3301   int i=0, current=0;
3302
3303   req[4] = N6110_GetMemoryType(entry->MemoryType);
3304   req[5] = entry->Location;
3305
3306   current=7;
3307
3308   if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {
3309
3310      req[6] = strlen(entry->Name)*2;
3311
3312      EncodeUnicode (req+current,entry->Name ,strlen(entry->Name));
3313      
3314      for (i=0; i<strlen(entry->Name); i++)
3315      {
3316        /* here we encode "special" chars */
3317        if (entry->Name[i]=='~') req[current+i*2]=1; //enables/disables blinking
3318        if (entry->Name[i]=='`') req[current+i*2]=0; //hides rest ot contents
3319      }
3320
3321      current+=strlen(entry->Name)*2;
3322   } else {
3323
3324     req[6] = strlen(entry->Name);
3325
3326     for (i=0; i<strlen(entry->Name); i++)
3327     {
3328       req[current+i] = entry->Name[i];
3329
3330       /* here we encode "special" chars */
3331       if (entry->Name[i]=='~') req[current+i]=1; //enables/disables blinking
3332       if (entry->Name[i]=='`') req[current+i]=0; //hides rest ot contents
3333     }
3334
3335     current+=strlen(entry->Name);
3336   }
3337
3338   req[current++]=strlen(entry->Number);
3339
3340   for (i=0; i<strlen(entry->Number); i++)
3341     req[current+i] = entry->Number[i];
3342
3343   current+=strlen(entry->Number);
3344
3345   /* Jano: This allow to save 14 characters name into SIM memory, when
3346      No Group is selected. */
3347   if (entry->Group == 5)
3348     req[current++]=0xff;
3349   else
3350     req[current++]=entry->Group;
3351
3352   return NULL_SendMessageSequence
3353     (50, &CurrentPhonebookError, current, 0x03, req);
3354 }
3355
3356 void N6110_ReplyNetmonitor(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3357
3358   switch(MessageBuffer[3]) {
3359
3360     case 0x00:
3361 #ifdef DEBUG
3362       fprintf(stdout, _("Message: Netmonitor correctly set.\n"));
3363 #endif /* DEBUG */
3364       CurrentNetmonitorError=GE_NONE;  
3365       break;
3366       
3367     default:
3368 #ifdef DEBUG
3369       fprintf(stdout, _("Message: Netmonitor menu %d received:\n"), MessageBuffer[3]);
3370       fprintf(stdout, "%s\n", MessageBuffer+4);
3371 #endif /* DEBUG */
3372
3373       strcpy(CurrentNetmonitor, MessageBuffer+4);
3374
3375       CurrentNetmonitorError=GE_NONE;  
3376   }
3377 }
3378
3379 GSM_Error N6110_NetMonitor(unsigned char mode, char *Screen)
3380 {
3381   unsigned char req[] = { 0x00, 0x01, 0x7e, 0x00 };
3382   
3383   GSM_Error error;
3384   
3385   error=N6110_EnableExtendedCommands(0x01);
3386   if (error!=GE_NONE) return error;
3387
3388   CurrentNetmonitor=Screen;
3389
3390   req[3]=mode;
3391
3392   return NULL_SendMessageSequence
3393     (20, &CurrentNetmonitorError, 4, 0x40, req);
3394 }
3395
3396 /* Doesn't work in N3210. */
3397 /* In other allow to access phone menu without SIM card (just send any sequence) */
3398 GSM_Error N6110_SendDTMF(char *String)
3399 {
3400   unsigned char req[64] = { N6110_FRAME_HEADER, 0x50,
3401                             0x00 /* Length of DTMF string. */
3402                           };
3403                           
3404   u8 length=strlen(String);
3405
3406   if (length>59) length=59;
3407   
3408   req[4] = length;
3409   
3410   memcpy(req+5,String,length);
3411
3412   return NULL_SendMessageSequence
3413     (20, &CurrentSendDTMFError, 5+length, 0x01, req);
3414 }
3415
3416 void N6110_ReplyGetSpeedDial(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3417
3418   switch (MessageBuffer[3]) {
3419
3420   case 0x17:
3421
3422     switch (MessageBuffer[4]) {
3423       case 0x02: CurrentSpeedDialEntry->MemoryType = GMT_ME;
3424       default  : CurrentSpeedDialEntry->MemoryType = GMT_SM;
3425     }
3426       
3427     CurrentSpeedDialEntry->Location = MessageBuffer[5];
3428
3429 #ifdef DEBUG
3430     fprintf(stdout, _("Message: Speed dial entry received:\n"));
3431     fprintf(stdout, _("   Location: %d\n"), CurrentSpeedDialEntry->Location);
3432     fprintf(stdout, _("   MemoryType: %s\n"), N6110_MemoryType_String[CurrentSpeedDialEntry->MemoryType]);
3433     fprintf(stdout, _("   Number: %d\n"), CurrentSpeedDialEntry->Number);
3434 #endif /* DEBUG */
3435
3436     CurrentSpeedDialError=GE_NONE;
3437     break;
3438
3439   case 0x18:
3440
3441 #ifdef DEBUG
3442     fprintf(stdout, _("Message: Speed dial entry error\n"));
3443 #endif /* DEBUG */
3444     CurrentSpeedDialError=GE_INVALIDSPEEDDIALLOCATION;
3445     break;
3446
3447   }
3448 }
3449
3450 GSM_Error N6110_GetSpeedDial(GSM_SpeedDial *entry)
3451 {
3452
3453   unsigned char req[] = { N6110_FRAME_HEADER,
3454                           0x16,
3455                           0x00  /* The number of speed dial. */
3456                         };
3457
3458   CurrentSpeedDialEntry = entry;
3459
3460   req[4] = entry->Number;
3461
3462   return NULL_SendMessageSequence
3463     (20, &CurrentSpeedDialError, 5, 0x03, req);
3464 }
3465
3466 void N6110_ReplySetSpeedDial(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3467
3468   switch (MessageBuffer[3]) {
3469
3470   case 0x1a:
3471
3472 #ifdef DEBUG
3473     fprintf(stdout, _("Message: Speed dial entry set.\n"));
3474 #endif /* DEBUG */
3475     CurrentSpeedDialError=GE_NONE;
3476     break;
3477
3478   case 0x1b:
3479
3480 #ifdef DEBUG
3481     fprintf(stdout, _("Message: Speed dial entry setting error.\n"));
3482 #endif /* DEBUG */
3483     CurrentSpeedDialError=GE_INVALIDSPEEDDIALLOCATION;
3484     break;
3485
3486   }
3487 }
3488
3489 GSM_Error N6110_SetSpeedDial(GSM_SpeedDial *entry)
3490 {
3491
3492   unsigned char req[] = { N6110_FRAME_HEADER,
3493                           0x19,
3494                           0x00, /* Number */
3495                           0x00, /* Memory Type */
3496                           0x00  /* Location */
3497                         };
3498
3499   req[4] = entry->Number;
3500
3501   switch (entry->MemoryType) {
3502     case GMT_ME: req[5] = 0x02;
3503     default    : req[5] = 0x03;
3504   }
3505
3506   req[6] = entry->Location;
3507
3508   return NULL_SendMessageSequence
3509     (20, &CurrentSpeedDialError, 7, 0x03, req);
3510 }
3511
3512 /* This function finds parts of SMS in frame used in new Nokia phones
3513    in internal protocols (they're coded according to GSM 03.40), copies them
3514    to GSM_ETSISMSMessage and calls GSM_DecodeETSISMS to decode
3515    GSM_ETSISMSMessage to GSM_SMSMessage structure */
3516 GSM_Error GSM_DecodeNokiaSMSFrame(GSM_SMSMessage *SMS, unsigned char *req, int length)
3517 {
3518   SMS_MessageType PDU=SMS_Deliver;
3519   GSM_ETSISMSMessage ETSI;
3520   int offset=0,i;
3521
3522   ETSI.firstbyte=req[12];
3523
3524   /* See GSM 03.40 section 9.2.3.1 */
3525   if ((ETSI.firstbyte & 0x03) == 0x01) PDU=SMS_Submit;
3526   if ((ETSI.firstbyte & 0x03) == 0x02) PDU=SMS_Status_Report;
3527
3528   switch (PDU) {
3529     case SMS_Submit       : offset=5;break;
3530     case SMS_Deliver      : offset=4;break;
3531     case SMS_Status_Report: offset=3;break;
3532     default:                break;
3533   }
3534
3535   for (i=0;i<req[0]+1;i++)
3536     ETSI.SMSCNumber[i]=req[i];
3537
3538   for (i=0;i<((req[12+offset]+1)/2+1)+1;i++)
3539     ETSI.Number[i]=req[i+12+offset];
3540
3541   switch (PDU) {
3542     case SMS_Submit:
3543       ETSI.TPDCS=req[10+offset];
3544       ETSI.TPUDL=req[11+offset];
3545       ETSI.TPVP=0;  //no support for now
3546       ETSI.TPPID=0; //no support for now
3547       for(i=31+offset;i<length;i++)
3548         ETSI.MessageText[i-31-offset]=req[i];
3549       break;
3550     case SMS_Deliver:
3551       ETSI.TPDCS=req[10+offset];
3552       ETSI.TPUDL=req[11+offset];
3553       ETSI.TPPID=0; //no support for now
3554       for(i=31+offset;i<length;i++)
3555         ETSI.MessageText[i-31-offset]=req[i];
3556       for(i=0;i<7;i++)
3557         ETSI.DeliveryDateTime[i]=req[i+24+offset];
3558       break;
3559     case SMS_Status_Report:
3560       for(i=0;i<7;i++)
3561         ETSI.DeliveryDateTime[i]=req[i+24+offset];
3562       ETSI.TPStatus=req[14];
3563       for(i=0;i<7;i++)
3564         ETSI.SMSCDateTime[i]=req[i+34];
3565       break;
3566     default:
3567       break;
3568   }
3569
3570   GSM_DecodeETSISMS(SMS, &ETSI);
3571
3572   SMS->Name[0]=0;
3573
3574   return GE_NONE;
3575 }
3576
3577 void N6110_ReplyGetSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3578
3579   int offset;
3580   
3581   switch (MessageBuffer[3]) {
3582
3583   case 0x08:
3584
3585     switch (MessageBuffer[7]) {
3586
3587       case 0x00:
3588         CurrentSMSMessage->Type = GST_SMS;
3589         CurrentSMSMessage->folder=GST_INBOX;
3590         offset=4;
3591         break;
3592
3593       case 0x01:
3594         CurrentSMSMessage->Type = GST_DR;
3595         CurrentSMSMessage->folder=GST_INBOX;
3596         offset=3;
3597         break;
3598
3599       case 0x02:
3600         CurrentSMSMessage->Type = GST_SMS;
3601         CurrentSMSMessage->folder=GST_OUTBOX;
3602         offset=5;
3603         break;
3604
3605       default:
3606         CurrentSMSMessage->Type = GST_UN;
3607         offset=4;
3608         break;
3609
3610     }
3611
3612     /* Field Short Message Status - MessageBuffer[4] seems not to be
3613        compliant with GSM 07.05 spec.
3614        Meaning     Nokia protocol       GMS spec
3615        ----------------------------------------------------
3616        MO Sent     0x05                 0x07 or 0x01
3617        MO Not sent 0x07                 0x06 or 0x00
3618        MT Read     0x01                 0x05 or 0x01
3619        MT Not read 0x03                 0x04 or 0x00
3620        ----------------------------------------------------
3621        See GSM 07.05 section 2.5.2.6 and correct me if I'm wrong.
3622        
3623                                          Pawel Kot */
3624
3625     if (MessageBuffer[4] & 0x02) CurrentSMSMessage->Status = GSS_NOTSENTREAD;
3626                             else CurrentSMSMessage->Status = GSS_SENTREAD;
3627
3628 #ifdef DEBUG
3629     fprintf(stdout, _("Number: %d\n"), MessageBuffer[6]);
3630
3631     if (CurrentSMSMessage->folder!=1) { //GST_OUTBOX
3632       fprintf(stdout, _("Message: Received SMS (mobile terminated)\n"));
3633     } else {
3634       fprintf(stdout, _("Message: Outbox message (mobile originated)\n"));
3635     }
3636
3637     if (CurrentSMSMessage->Type == GST_DR) fprintf(stdout, _("   Delivery Report\n"));
3638     if (CurrentSMSMessage->Type == GST_UN) fprintf(stdout, _("   Unknown type\n"));
3639
3640     if (CurrentSMSMessage->folder==1) { //GST_OUTBOX
3641       if (CurrentSMSMessage->Status) fprintf(stdout, _("   Sent\n"));
3642                                 else fprintf(stdout, _("   Not sent\n"));
3643     } else {
3644       if (CurrentSMSMessage->Status) fprintf(stdout, _("   Read\n"));
3645                                 else fprintf(stdout, _("   Not read\n"));
3646     }
3647 #endif
3648
3649     CurrentSMSPointer=GSM_DecodeNokiaSMSFrame(CurrentSMSMessage, MessageBuffer+8, MessageLength-8);
3650
3651     CurrentSMSMessage->MemoryType = MessageBuffer[5];
3652     CurrentSMSMessage->MessageNumber = MessageBuffer[6];
3653  
3654     /* Signal no error to calling code. */
3655     CurrentSMSMessageError = GE_NONE;
3656
3657 #ifdef DEBUG
3658     fprintf(stdout, "\n");
3659 #endif
3660
3661     break;
3662
3663   case 0x09:
3664
3665     /* We have requested invalid or empty location. */
3666
3667 #ifdef DEBUG
3668     fprintf(stdout, _("Message: SMS reading failed\n"));
3669
3670     switch (MessageBuffer[4]) {
3671       case 0x02:
3672         fprintf(stdout, _("   Invalid location!\n"));break;
3673       case 0x07:
3674         fprintf(stdout, _("   Empty SMS location.\n"));break;
3675       case 0x0c:
3676         fprintf(stdout, _("   No access to memory (no PIN on card ?)\n"));break;
3677       default:      
3678         fprintf(stdout, _("   Error code %i - please report it \n"),MessageBuffer[4]);break;
3679     }
3680 #endif /* DEBUG */
3681
3682     switch (MessageBuffer[4]) {
3683       case 0x02:CurrentSMSMessageError = GE_INVALIDSMSLOCATION;break;
3684       case 0x07:CurrentSMSMessageError = GE_EMPTYSMSLOCATION;break;
3685       case 0x0c:CurrentSMSMessageError = GE_NOACCESS;break;
3686       default  :CurrentSMSMessageError = GE_UNKNOWN;break;
3687     }
3688
3689     break;
3690
3691   }
3692 }
3693
3694 GSM_Error N6110_GetSMSMessage(GSM_SMSMessage *message)
3695 {
3696
3697   unsigned char req[] = { N6110_FRAME_HEADER,
3698                           0x07,
3699                           0x02, /* Unknown */
3700                           0x00, /* Location */
3701                           0x01, 0x64};
3702
3703   int timeout = 60;
3704
3705   /* State machine code writes data to these variables when it comes in. */
3706
3707   CurrentSMSMessage = message;
3708   CurrentSMSMessageError = GE_BUSY;
3709
3710   req[5] = message->Location;
3711
3712   /* Send request */
3713   Protocol->SendMessage(8, 0x02, req);
3714
3715   /* Wait for timeout or other error. */
3716   while (timeout != 0 && (CurrentSMSMessageError == GE_BUSY || CurrentSMSMessageError == GE_SMSWAITING)) {
3717
3718     if (--timeout == 0)
3719       return (GE_TIMEOUT);
3720
3721     usleep (100000);
3722   }
3723
3724   return (CurrentSMSMessageError);
3725 }
3726
3727 void N6110_ReplyDeleteSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3728
3729 #ifdef DEBUG
3730   fprintf(stdout, _("Message: SMS deleted successfully.\n"));
3731 #endif /* DEBUG */
3732
3733   CurrentSMSMessageError = GE_NONE;     
3734 }
3735
3736 GSM_Error N6110_DeleteSMSMessage(GSM_SMSMessage *message)
3737 {
3738   unsigned char req[] = {N6110_FRAME_HEADER, 0x0a, 0x02, 0x00};
3739
3740   req[5] = message->Location;
3741
3742   return NULL_SendMessageSequence
3743     (50, &CurrentSMSMessageError, 6, 0x14, req);
3744 }
3745
3746 /* FIXME: do we need more than SMS_Submit and SMS_Deliver ? */
3747 GSM_Error GSM_EncodeNokiaSMSFrame(GSM_SMSMessage *SMS, unsigned char *req, int *length, SMS_MessageType PDU)
3748 {
3749   GSM_ETSISMSMessage ETSI;
3750   int i,offset=0;
3751
3752   GSM_EncodeETSISMS(SMS, &ETSI, PDU, length);
3753
3754   /* Cleaning */
3755   for (i=0;i<36;i++) req[i]=0;
3756
3757   req[12]=ETSI.firstbyte;
3758
3759   for (i=0;i<ETSI.SMSCNumber[0]+1;i++)
3760     req[i]=ETSI.SMSCNumber[i];
3761
3762   switch (PDU) {
3763     case SMS_Submit:
3764       offset=5;
3765       for (i=0;i<((ETSI.Number[0]+1)/2+1)+1;i++)
3766         req[i+12+offset]=ETSI.Number[i];
3767       req[10+offset]=ETSI.TPDCS;
3768       req[11+offset]=ETSI.TPUDL;
3769       req[24+offset]=ETSI.TPVP;
3770 #ifdef DEBUG
3771 //      fprintf(stdout,_("   First byte: %02x\n"),ETSI.firstbyte);
3772 //      fprintf(stdout,_("   TP-VP: %02x\n"),ETSI.TPVP);
3773 //      fprintf(stdout,_("   TP-DCS: %02x\n"),ETSI.TPDCS);
3774 #endif
3775 //    req[]=ETSI.TPPID;
3776       for(i=0;i<*length;i++)
3777         req[i+31+offset]=ETSI.MessageText[i];
3778       break;
3779
3780     case SMS_Deliver:
3781       offset=4;
3782       for (i=0;i<((ETSI.Number[0]+1)/2+1)+1;i++)
3783         req[i+12+offset]=ETSI.Number[i];
3784       req[10+offset]=ETSI.TPDCS;
3785       req[11+offset]=ETSI.TPUDL;
3786 //    req[]=ETSI.TPPID;
3787       for(i=0;i<*length;i++)
3788         req[i+31+offset]=ETSI.MessageText[i];
3789       for (i=0;i<7;i++)
3790         req[24+offset+i]=ETSI.DeliveryDateTime[i];
3791       break;
3792     default:
3793       break;
3794   }
3795   
3796   *length=*length+offset;
3797   
3798   return GE_NONE;
3799 }
3800
3801 void N6110_ReplySendSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3802     
3803   switch (MessageBuffer[3]) {
3804
3805   /* SMS message correctly sent to the network */
3806   case 0x02:
3807 #ifdef DEBUG
3808     fprintf(stdout, _("Message: SMS Message correctly sent.\n"));
3809 #endif /* DEBUG */
3810     CurrentSMSMessageError = GE_SMSSENDOK;
3811     break;
3812
3813   /* SMS message send to the network failed */
3814   case 0x03:
3815
3816 #ifdef DEBUG
3817     fprintf(stdout, _("Message: Sending SMS Message failed, error: %i"),MessageBuffer[6]);
3818       
3819     switch (MessageBuffer[6]) {
3820       case 1: fprintf(stdout,_(" (info \"Number not in use\")"));break;
3821       case 21: fprintf(stdout,_(" (info \"Message not sent this time\")"));break;
3822       case 28: fprintf(stdout,_(" (info \"Number not in use\")"));break;
3823       case 38: fprintf(stdout,_(" (info \"Message not sent this time\")"));break;       case 50: fprintf(stdout,_(" (info \"Check operator services\")"));break;        
3824       case 96: fprintf(stdout,_(" (info \"Message sending failed\")"));break;   
3825       case 111: fprintf(stdout,_(" (info \"Message sending failed\")"));break;  
3826       case 166: fprintf(stdout,_(" (info \"Message sending failed\")"));break;  
3827       case 178: fprintf(stdout,_(" (info \"Message sending failed\")"));break;  
3828       case 252: fprintf(stdout,_(" (info \"Message sending failed\")"));break;         case 253: fprintf(stdout,_(" (info \"Message sending failed\")"));break; 
3829     }
3830
3831     fprintf(stdout,_("\n   For more details with errors see netmonitor manual (test 65) on www.marcin-wiacek.topnet.pl"));
3832     fprintf(stdout,_("\n   If know their meaning, GSM specs decribing them, contact with me on marcin-wiacek@topnet.pl. THX\n"));
3833 #endif /* DEBUG */
3834
3835     CurrentSMSMessageError = GE_SMSSENDFAILED;
3836     break;
3837
3838   }
3839 }
3840
3841 GSM_Error N6110_SendSMSMessage(GSM_SMSMessage *SMS)
3842 {
3843   GSM_Error error;
3844
3845   unsigned char req[256] = {
3846     N6110_FRAME_HEADER,
3847     0x01, 0x02, 0x00, /* SMS send request*/
3848   };
3849
3850   int length;
3851
3852   error=GSM_EncodeNokiaSMSFrame(SMS, req+6, &length, SMS_Submit);    
3853   if (error != GE_NONE) return error;
3854
3855   return NULL_SendMessageSequence
3856     (200, &CurrentSMSMessageError, 42+length, 0x02, req);
3857 }
3858
3859 void N6110_ReplySaveSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3860
3861   switch (MessageBuffer[3]) {
3862
3863   case 0x05:
3864       
3865 #ifdef DEBUG
3866     fprintf(stdout, _("SMS Message stored at %d\n"), MessageBuffer[5]);
3867 #endif
3868       
3869     CurrentSMSMessage->MessageNumber=MessageBuffer[5];
3870       
3871     CurrentSMSMessageError = GE_NONE;
3872     break;
3873
3874   case 0x06:
3875 #ifdef DEBUG
3876     fprintf(stdout, _("SMS saving failed\n"));
3877     switch (MessageBuffer[4]) {
3878       case 0x02:fprintf(stdout, _("   All locations busy.\n"));break;
3879       case 0x03:fprintf(stdout, _("   Invalid location!\n"));break;
3880       default  :fprintf(stdout, _("   Unknown error.\n"));break;
3881     }
3882 #endif      
3883       
3884     switch (MessageBuffer[4]) {
3885       case 0x02:CurrentSMSMessageError = GE_MEMORYFULL;break;
3886       case 0x03:CurrentSMSMessageError = GE_INVALIDSMSLOCATION;break;
3887       default  :CurrentSMSMessageError = GE_UNKNOWN;break;
3888     }
3889   }
3890 }
3891
3892 /* GST_DR and GST_UN not supported ! */
3893 GSM_Error N6110_SaveSMSMessage(GSM_SMSMessage *SMS)
3894 {
3895   unsigned char req[256] = {
3896     N6110_FRAME_HEADER, 0x04, /* SMS save request*/
3897     0x00, /* SMS Status. Different for Inbox and Outbox */
3898     0x02, /* ?? */
3899     0x00, /* SMS Location */
3900     0x02, /* SMS Type */
3901   };
3902
3903   int length;
3904   SMS_MessageType PDU;
3905   GSM_Error error;
3906
3907   if (SMS->Location) req[6] = SMS->Location;
3908     
3909   if (SMS->folder==0) { /*Inbox*/
3910     req[4]=1;      /* SMS Status */
3911     req[7] = 0x00; /* SMS Type */
3912     PDU=SMS_Deliver;
3913   } else {
3914     req[4]=5;      /* SMS Status */
3915     req[7] = 0x02; /* SMS Type */
3916     PDU=SMS_Submit;
3917   }
3918   
3919   if (SMS->Status == GSS_NOTSENTREAD) req[4] |= 0x02;  
3920
3921   error=GSM_EncodeNokiaSMSFrame(SMS, req+8, &length, PDU);  
3922   if (error != GE_NONE) return error;
3923
3924   CurrentSMSMessage = SMS;
3925
3926   return NULL_SendMessageSequence
3927     (70, &CurrentSMSMessageError, 39+length, 0x14, req);
3928 }
3929
3930 void N6110_ReplySetCellBroadcast(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3931
3932 #ifdef DEBUG
3933   fprintf(stdout, _("Message: Cell Broadcast enabled/disabled successfully.\n")); fflush (stdout);
3934 #endif
3935
3936   CurrentCBError = GE_NONE;
3937 }
3938
3939 /* Enable and disable Cell Broadcasting */
3940 GSM_Error N6110_EnableCellBroadcast(void)
3941 {
3942   unsigned char req[] = {N6110_FRAME_HEADER, 0x20,
3943                          0x01, 0x01, 0x00, 0x00, 0x01, 0x01};
3944
3945 #ifdef DEBUG
3946   fprintf (stdout,"Enabling CB\n");
3947 #endif
3948
3949   CurrentCBMessage = (GSM_CBMessage *)malloc(sizeof (GSM_CBMessage));
3950   CurrentCBMessage->Channel = 0;
3951   CurrentCBMessage->New = false;
3952   strcpy (CurrentCBMessage->Message,"");
3953
3954   return NULL_SendMessageSequence
3955     (10, &CurrentCBError, 10, 0x02, req);
3956 }
3957
3958
3959 GSM_Error N6110_DisableCellBroadcast(void)
3960 {
3961   /* Should work, but not tested fully */
3962
3963   unsigned char req[] = {N6110_FRAME_HEADER, 0x20,
3964                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /*VERIFY*/
3965
3966   return NULL_SendMessageSequence
3967     (10, &CurrentCBError, 10, 0x02, req);
3968 }
3969
3970 void N6110_ReplyReadCellBroadcast(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3971
3972   int i, tmp;
3973   unsigned char output[160];
3974   
3975   CurrentCBMessage->Channel = MessageBuffer[7];
3976   CurrentCBMessage->New = true;
3977   tmp=GSM_UnpackEightBitsToSeven(0, MessageBuffer[9], MessageBuffer[9], MessageBuffer+10, output);
3978
3979 #ifdef DEBUG
3980   fprintf(stdout, _("Message: CB received.\n")); fflush (stdout);
3981
3982   fprintf(stdout, _("Message: channel number %i\n"),MessageBuffer[7]);
3983
3984   fflush (stdout);
3985
3986   for (i=0; i<tmp;i++) {
3987     fprintf(stdout, "%c", DecodeWithDefaultAlphabet(output[i]));
3988   }
3989
3990   fprintf(stdout, "\n");
3991 #endif
3992    
3993   for (i=0; i<tmp; i++) {
3994     CurrentCBMessage->Message[i] = DecodeWithDefaultAlphabet(output[i]);
3995   }
3996   CurrentCBMessage->Message[i]=0;
3997 }
3998
3999 GSM_Error N6110_ReadCellBroadcast(GSM_CBMessage *Message)
4000 {
4001 #ifdef DEBUG
4002    fprintf(stdout,"Reading CB\n");
4003 #endif
4004
4005   if (CurrentCBMessage != NULL) 
4006   {
4007     if (CurrentCBMessage->New == true)
4008     {
4009 #ifdef DEBUG
4010   fprintf(stdout,"New CB received\n");
4011 #endif
4012       Message->Channel = CurrentCBMessage->Channel;
4013       strcpy(Message->Message,CurrentCBMessage->Message);
4014       CurrentCBMessage->New = false;
4015       return (GE_NONE);
4016     }
4017   }
4018   return (GE_NONEWCBRECEIVED);
4019 }
4020
4021 int N6110_MakeCallerGroupFrame(unsigned char *req,GSM_Bitmap Bitmap)
4022 {
4023   int count=0;
4024
4025   req[count++]=Bitmap.number;
4026   req[count++]=strlen(Bitmap.text);
4027   memcpy(req+count,Bitmap.text,req[count-1]);
4028   count+=req[count-1];
4029   req[count++]=Bitmap.ringtone;
4030
4031   /* Setting for graphic:
4032      0x00 - Off
4033      0x01 - On
4034      0x02 - View Graphics
4035      0x03 - Send Graphics
4036      0x04 - Send via IR
4037      You can even set it higher but Nokia phones (my
4038      6110 at least) will not show you the name of this
4039      item in menu ;-)) Nokia is really joking here. */
4040   if (Bitmap.enabled) req[count++]=0x01;
4041                  else req[count++]=0x00;
4042
4043   req[count++]=(Bitmap.size+4)>>8;
4044   req[count++]=(Bitmap.size+4)%0xff;
4045   req[count++]=0x00;  /* Future extensions! */
4046   req[count++]=Bitmap.width;
4047   req[count++]=Bitmap.height;
4048   req[count++]=0x01;  /* Just BW */
4049   memcpy(req+count,Bitmap.bitmap,Bitmap.size);
4050
4051   return count+Bitmap.size;
4052 }
4053
4054 int N6110_MakeOperatorLogoFrame(unsigned char *req,GSM_Bitmap Bitmap)
4055 {
4056   int count=0;
4057
4058   EncodeNetworkCode(req+count, Bitmap.netcode);
4059   count=count+3;
4060
4061   req[count++]=(Bitmap.size+4)>>8;
4062   req[count++]=(Bitmap.size+4)%0xff;
4063   req[count++]=0x00;  /* Infofield */
4064   req[count++]=Bitmap.width;
4065   req[count++]=Bitmap.height;
4066   req[count++]=0x01;  /* Just BW */    
4067   memcpy(req+count,Bitmap.bitmap,Bitmap.size);
4068
4069   return count+Bitmap.size;
4070 }
4071
4072 int N6110_MakeStartupLogoFrame(unsigned char *req,GSM_Bitmap Bitmap)
4073 {
4074   int count=0;
4075
4076   req[count++]=0x01;
4077   req[count++]=Bitmap.height;
4078   req[count++]=Bitmap.width;
4079   memcpy(req+count,Bitmap.bitmap,Bitmap.size);
4080
4081   return count+Bitmap.size;
4082 }
4083
4084 /* Set a bitmap or welcome-note */
4085 GSM_Error N6110_SetBitmap(GSM_Bitmap *Bitmap) {
4086
4087   unsigned char req[600] = { N6110_FRAME_HEADER };
4088   u16 count=3;
4089   u8 textlen;
4090   
4091   int timeout=50;
4092
4093   /* Direct uploading variables */
4094   GSM_MultiSMSMessage SMS;
4095   unsigned char buffer[1000] = {0x0c,0x01};
4096   GSM_NetworkInfo NetworkInfo;
4097
4098   GSM_Error error;
4099  
4100   /* Uploading with preview */
4101   if (Bitmap->number==255 &&
4102      (Bitmap->type==GSM_OperatorLogo || Bitmap->type==GSM_CallerLogo)) {
4103     GSM_SaveBitmapToSMS(&SMS,Bitmap,false,false);
4104     memcpy(buffer+2,SMS.SMS[0].UDH,SMS.SMS[0].UDH[0]+1);
4105
4106     memcpy(buffer+2+SMS.SMS[0].UDH[0]+1,SMS.SMS[0].MessageText,SMS.SMS[0].Length);
4107
4108     buffer[2+SMS.SMS[0].UDH[0]+1+SMS.SMS[0].Length]=0x00;
4109
4110     Protocol->SendMessage(2+SMS.SMS[0].UDH[0]+1+SMS.SMS[0].Length+1, 0x12, buffer);
4111
4112     GSM->GetNetworkInfo(&NetworkInfo); //need to make something
4113     return GE_NONE; //no answer from phone
4114   }
4115  
4116   CurrentSetBitmapError = GE_BUSY;  
4117   
4118   switch (Bitmap->type) {
4119   case GSM_WelcomeNoteText:
4120   case GSM_DealerNoteText:
4121     req[count++]=0x18;
4122     req[count++]=0x01; /* Only one block */
4123
4124     if (Bitmap->type==GSM_WelcomeNoteText)
4125       req[count++]=0x02; /* Welcome text */
4126     else
4127       req[count++]=0x03; /* Dealer Welcome Note */
4128
4129     textlen=strlen(Bitmap->text);
4130     req[count++]=textlen;
4131     memcpy(req+count,Bitmap->text,textlen);
4132       
4133     count+=textlen;
4134
4135     Protocol->SendMessage(count, 0x05, req);
4136     
4137     break;
4138
4139   case GSM_StartupLogo:
4140     if (Bitmap->number==0) {
4141
4142       /* For 33xx we first set animated logo to default */
4143       if (GetModelFeature (FN_STARTUP)==F_STANIM) {
4144         error=N6110_SetProfileFeature(0, 0x29, Bitmap->number);
4145         if (error!=GE_NONE) return error;
4146       }
4147
4148       req[count++]=0x18;
4149       req[count++]=0x01; /* Only one block */
4150       count=count+N6110_MakeStartupLogoFrame(req+5,*Bitmap); 
4151       Protocol->SendMessage(count, 0x05, req);
4152     } else {
4153       return N6110_SetProfileFeature(0, 0x29, Bitmap->number);
4154     }
4155     break;
4156
4157   case GSM_OperatorLogo:
4158     req[count++]=0x30;  /* Store Op Logo */
4159     req[count++]=0x01;  /* Location */
4160     count=count+N6110_MakeOperatorLogoFrame(req+5,*Bitmap); 
4161     Protocol->SendMessage(count, 0x05, req);
4162     break;
4163
4164   case GSM_CallerLogo:
4165     req[count++]=0x13;
4166     count=count+N6110_MakeCallerGroupFrame(req+4,*Bitmap);
4167     Protocol->SendMessage(count, 0x03, req);
4168     break;
4169
4170   case GSM_PictureImage:
4171     req[count++]=0x03;
4172     req[count++]=Bitmap->number;
4173     if (strcmp(Bitmap->Sender,"")) {
4174        req[count]=GSM_PackSemiOctetNumber(Bitmap->Sender, req+count+1,true);
4175
4176        /* Convert number of semioctets to number of chars and add count */
4177        textlen=req[count];
4178        if (textlen % 2) textlen++;
4179        count+=textlen / 2 + 1;
4180
4181        count++;
4182     } else {
4183       req[count++]=0x00;
4184       req[count++]=0x00;
4185     }
4186     req[count++]=0x00;
4187     req[count++]=strlen(Bitmap->text);
4188     memcpy(req+count,Bitmap->text,strlen(Bitmap->text));
4189     count+=strlen(Bitmap->text);
4190     req[count++]=0x00;
4191     req[count++]=Bitmap->width;
4192     req[count++]=Bitmap->height;
4193     req[count++]=0x01;
4194     memcpy(req+count,Bitmap->bitmap,Bitmap->size);
4195     Protocol->SendMessage(count+Bitmap->size, 0x47, req);
4196     break;
4197
4198   case GSM_7110OperatorLogo:
4199   case GSM_7110StartupLogo:
4200   case GSM_6210StartupLogo:
4201     return GE_NOTSUPPORTED;
4202
4203   case GSM_None:
4204     return GE_NONE;
4205   }
4206
4207   /* Wait for timeout or other error. */
4208   while (timeout != 0 && CurrentSetBitmapError == GE_BUSY ) {
4209           
4210     if (--timeout == 0)
4211       return (GE_TIMEOUT);
4212                     
4213     usleep (100000);
4214   }
4215
4216   return CurrentSetBitmapError;
4217 }
4218
4219 /* Get a bitmap from the phone */
4220 GSM_Error N6110_GetBitmap(GSM_Bitmap *Bitmap) {
4221
4222   unsigned char req[10] = { N6110_FRAME_HEADER };
4223   u8 count=3;
4224   
4225   int timeout=100;
4226   
4227   CurrentGetBitmap=Bitmap; 
4228   CurrentGetBitmapError = GE_BUSY;  
4229   
4230   switch (CurrentGetBitmap->type) {
4231   case GSM_StartupLogo:
4232   case GSM_WelcomeNoteText:
4233   case GSM_DealerNoteText:
4234     req[count++]=0x16;
4235     Protocol->SendMessage(count, 0x05, req);
4236     break;
4237   case GSM_OperatorLogo:
4238     req[count++]=0x33;
4239     req[count++]=0x01; /* Location 1 */
4240     Protocol->SendMessage(count, 0x05, req);
4241     break;
4242   case GSM_CallerLogo:
4243     req[count++]=0x10;
4244     req[count++]=Bitmap->number;
4245     Protocol->SendMessage(count, 0x03, req);
4246     break;
4247   case GSM_PictureImage:
4248     req[count++]=0x01;
4249     req[count++]=Bitmap->number;
4250     Protocol->SendMessage(count, 0x47, req);
4251     break;
4252   case GSM_7110OperatorLogo:
4253   case GSM_7110StartupLogo:
4254   case GSM_6210StartupLogo:
4255   default:
4256     return GE_NOTSUPPORTED;
4257   }
4258
4259   /* Wait for timeout or other error. */
4260   while (timeout != 0 && CurrentGetBitmapError == GE_BUSY ) {
4261           
4262     if (--timeout == 0)
4263       return (GE_TIMEOUT);
4264                     
4265     usleep (100000);
4266   }
4267
4268   CurrentGetBitmap=NULL;
4269
4270   return CurrentGetBitmapError;
4271 }
4272
4273 void N6110_ReplySetRingtone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4274
4275   switch (MessageBuffer[3]) {
4276
4277   /* Set ringtone OK */
4278   case 0x37:       
4279 #ifdef DEBUG
4280     fprintf(stdout, _("Message: Ringtone set OK!\n"));
4281 #endif  
4282     CurrentRingtoneError=GE_NONE; 
4283     break;      
4284
4285   /* Set ringtone error */
4286   case 0x38:       
4287 #ifdef DEBUG
4288     fprintf(stdout, _("Message: Ringtone setting error !\n"));
4289 #endif  
4290     CurrentRingtoneError=GE_NOTSUPPORTED; 
4291     break;      
4292   }
4293 }
4294
4295 GSM_Error N6110_SetRingTone(GSM_Ringtone *ringtone, int *maxlength)
4296 {
4297   
4298   char req[FB61_MAX_RINGTONE_FRAME_LENGTH+10] =
4299       {N6110_FRAME_HEADER,
4300        0x36,
4301        0x00,  /* Location */
4302        0x00,0x78};
4303
4304   int size=FB61_MAX_RINGTONE_FRAME_LENGTH;
4305  
4306   /* Variables for preview uploading */
4307   unsigned char buffer[FB61_MAX_RINGTONE_FRAME_LENGTH+50];
4308   unsigned char buffer2[20];
4309   GSM_NetworkInfo NetworkInfo;
4310
4311   /* Setting ringtone with preview */
4312   if (ringtone->location==255) {
4313     buffer[0]=0x0c;
4314     buffer[1]=0x01;
4315     EncodeUDHHeader(buffer2, GSM_RingtoneUDH);
4316     memcpy(buffer+2,buffer2,buffer2[0]+1); //copying UDH
4317     *maxlength=GSM_PackRingtone(ringtone, buffer+2+buffer2[0]+1, &size); //packing ringtone
4318     Protocol->SendMessage(2+buffer2[0]+1+size, 0x12, buffer); //sending frame
4319     GSM->GetNetworkInfo(&NetworkInfo); //need to make something
4320     sleep(1);
4321     return GE_NONE; //no answer from phone
4322   }
4323   
4324   *maxlength=GSM_PackRingtone(ringtone, req+7, &size);
4325
4326   req[4]=ringtone->location-1;
4327
4328   return NULL_SendMessageSequence
4329     (50, &CurrentRingtoneError, (size+7), 0x05, req);
4330 }
4331
4332 void N6110_ReplyGetBinRingtone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4333
4334   int i;
4335   
4336   switch (MessageBuffer[4]) {
4337     case 0x00: /* location supported. We have ringtone */
4338
4339       /* Binary format used in N6150 */
4340       if (MessageBuffer[5]==0x0c && MessageBuffer[6]==0x01 && MessageBuffer[7]==0x2c) {
4341 #ifdef DEBUG
4342         fprintf(stdout,_("Message: ringtone \""));
4343 #endif      
4344
4345         /* Copying name */
4346         i=8;
4347         while (true) {
4348 #ifdef DEBUG
4349           if (MessageBuffer[i]!=0)
4350             fprintf(stdout,_("%c"),MessageBuffer[i]);
4351 #endif
4352           CurrentGetBinRingtone->name[i-8]=MessageBuffer[i];
4353           if (MessageBuffer[i]==0) break;
4354           i++;
4355         }
4356
4357 #ifdef DEBUG    
4358         fprintf(stdout,_("\" received from location %i\n"),MessageBuffer[3]+1);
4359 #endif
4360       
4361         /* Looking for end */
4362         i=0;
4363         while (true) {
4364           if (MessageBuffer[i]==0x07 && MessageBuffer[i+1]==0x0b) {
4365             i=i+2;break;
4366           }
4367           if (MessageBuffer[i]==0x0e && MessageBuffer[i+1]==0x0b) {
4368             i=i+2;break;
4369           }
4370           i++;
4371           if (i==MessageLength) break;
4372         }
4373           
4374         /* Copying frame */
4375         memcpy(CurrentGetBinRingtone->frame,MessageBuffer+3,i-3);
4376         CurrentGetBinRingtone->length=i-3;
4377       
4378         CurrentBinRingtoneError=GE_NONE;
4379         break;
4380       }
4381           
4382       /* Binary format used in N3210 */
4383       if (MessageBuffer[5]==0x10 && MessageBuffer[6]==0x01 && MessageBuffer[7]==0x2c) {      
4384
4385 #ifdef DEBUG
4386         fprintf(stdout,_("Message: ringtone \""));
4387 #endif      
4388
4389         /* Copying name */
4390         i=8;
4391         while (true) {
4392 #ifdef DEBUG
4393           if (MessageBuffer[i]!=0)
4394             fprintf(stdout,_("%c"),MessageBuffer[i]);
4395 #endif
4396           CurrentGetBinRingtone->name[i-8]=MessageBuffer[i];
4397           if (MessageBuffer[i]==0) break;
4398           i++;
4399         }
4400
4401 #ifdef DEBUG    
4402         fprintf(stdout,_("\" received from location %i\n"),MessageBuffer[3]+1);
4403 #endif
4404
4405         /* Here changes to get full compatibility with binary format used in N6150 */
4406         MessageBuffer[3]=0;
4407         MessageBuffer[4]=0;
4408         MessageBuffer[5]=0x0c;
4409         MessageBuffer[6]=0x01;
4410         MessageBuffer[7]=0x2c;
4411
4412         /* Looking for end */
4413         i=0;
4414         while (true) {
4415           if (MessageBuffer[i]==0x07 && MessageBuffer[i+1]==0x0b) {
4416             i=i+2;break;
4417           }
4418           if (MessageBuffer[i]==0x0e && MessageBuffer[i+1]==0x0b) {
4419             i=i+2;break;
4420           }
4421           i++;
4422           if (i==MessageLength) break;
4423         }
4424           
4425         /* Copying frame */
4426         memcpy(CurrentGetBinRingtone->frame,MessageBuffer+3,i-3);
4427
4428         CurrentGetBinRingtone->length=i-3;
4429             
4430         CurrentBinRingtoneError=GE_NONE;          
4431         break;
4432       }
4433
4434       /* Copying frame */
4435       memcpy(CurrentGetBinRingtone->frame,MessageBuffer,MessageLength);
4436
4437       CurrentGetBinRingtone->length=MessageLength;
4438
4439 #ifdef DEBUG    
4440       fprintf(stdout,_("Message: unknown binary format for ringtone received from location %i\n"),MessageBuffer[3]+1);
4441 #endif
4442       CurrentBinRingtoneError=GE_UNKNOWNMODEL;
4443       break;
4444
4445     default:
4446
4447 #ifdef DEBUG
4448       fprintf(stdout,_("Message: Phone doesn't support downloaded ringtones at location %i\n"),MessageBuffer[3]+1);
4449 #endif
4450
4451       CurrentBinRingtoneError=GE_INVALIDRINGLOCATION;  
4452   }
4453 }
4454
4455 GSM_Error N6110_GetBinRingTone(GSM_BinRingtone *ringtone)
4456 {
4457   unsigned char req[] = { 0x00,0x01,0x9e,
4458                           0x00 }; //location
4459
4460   GSM_Error error;
4461   
4462   CurrentGetBinRingtone=ringtone;
4463   
4464   error=N6110_EnableExtendedCommands(0x01);
4465   if (error!=GE_NONE) return error;
4466
4467   req[3]=ringtone->location-1;
4468   
4469   return NULL_SendMessageSequence
4470     (50, &CurrentBinRingtoneError, 4, 0x40, req);
4471 }
4472
4473 void N6110_ReplySetBinRingtone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4474
4475   switch (MessageBuffer[4]) {
4476     case 0x00: /* location supported. We set ringtone */
4477 #ifdef DEBUG
4478       fprintf(stdout,_("Message: downloaded ringtone set at location %i\n"),MessageBuffer[3]+1);
4479 #endif
4480       CurrentBinRingtoneError=GE_NONE;
4481       break;
4482
4483     default:
4484 #ifdef DEBUG
4485       fprintf(stdout,_("Message: Phone doesn't support downloaded ringtones at location %i\n"),MessageBuffer[3]+1);
4486 #endif
4487       CurrentBinRingtoneError=GE_NOTSUPPORTED;    
4488       break;
4489   }
4490 }
4491
4492 GSM_Error N6110_SetBinRingTone(GSM_BinRingtone *ringtone)
4493 {
4494   unsigned char req[1000] = { 0x00,0x01,0xa0};
4495
4496   GSM_Error error;
4497
4498   GSM_BinRingtone ring;
4499
4500   /* Must be sure, that can upload ringtone to this phone */
4501   ring.location=ringtone->location;
4502   error=N6110_GetBinRingTone(&ring);
4503   if (error!=GE_NONE) return error;
4504     
4505   error=N6110_EnableExtendedCommands(0x01);
4506   if (error!=GE_NONE) return error;
4507   
4508   memcpy(req+3,ringtone->frame,ringtone->length);
4509
4510   req[3]=ringtone->location-1;
4511   
4512   return NULL_SendMessageSequence
4513     (50, &CurrentBinRingtoneError, ringtone->length+3, 0x40, req);
4514 }
4515
4516 GSM_Error N6110_Reset(unsigned char type)
4517 {  
4518   return N6110_EnableExtendedCommands(type);
4519 }
4520
4521 void N6110_Dispatch0x01Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4522
4523   int tmp, count;
4524           
4525   switch (MessageBuffer[3]) {
4526
4527   /* Unknown message - it has been seen after the 0x07 message (call
4528      answered). Probably it has similar meaning. If you can solve
4529      this - just mail me. Pavel Janík ml.
4530
4531      The message looks like this:
4532
4533      Msg Destination: PC
4534      Msg Source: Phone
4535      Msg Type: 01
4536      Msg Unknown: 00
4537      Msg Len: 0e
4538
4539      Phone: [01 ][08 ][00 ] is the header of the frame
4540
4541      [03 ] is the call message subtype
4542
4543      [05 ] is the call sequence number
4544
4545      [05 ] unknown 
4546
4547      [00 ][01 ][03 ][02 ][91][00] are unknown but has been
4548      seen in the Incoming call message (just after the
4549      caller's name from the phonebook). But never change
4550      between phone calls :-(
4551   */
4552
4553   /* This may mean sequence number of 'just made' call - CK */
4554   case 0x02:
4555
4556 #ifdef DEBUG
4557     fprintf(stdout, _("Message: Call message, type 0x02:"));
4558     fprintf(stdout, _("   Exact meaning not known yet, sorry :-(\n"));
4559 #endif /* DEBUG */
4560
4561     break;
4562
4563   /* Possibly call OK */
4564   /* JD: I think that this means "call in progress" (incomming or outgoing) */
4565   case 0x03:
4566     
4567 #ifdef DEBUG
4568     fprintf(stdout, _("Message: Call message, type 0x03:"));
4569     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4570     fprintf(stdout, _("   Exact meaning not known yet, sorry :-(\n"));
4571 #endif /* DEBUG */
4572     
4573     CurrentCallSequenceNumber=MessageBuffer[4];
4574     CurrentIncomingCall[0]='D';
4575     if (CurrentCallPassup) CurrentCallPassup('D');
4576
4577     break;
4578
4579   /* Remote end has gone away before you answer the call.  Probably your
4580      mother-in-law or banker (which is worse?) ... */
4581   case 0x04:
4582
4583 #ifdef DEBUG
4584     fprintf(stdout, _("Message: Remote end hang up.\n"));
4585     fprintf(stdout, _("   Sequence nr. of the call: %d, error: %i"), MessageBuffer[4],MessageBuffer[6]);
4586
4587     switch (MessageBuffer[6]) {
4588       case 28: fprintf(stdout,_(" (info \"Invalid phone number\")"));break;
4589       case 34: fprintf(stdout,_(" (info \"Network busy\")"));break;
4590       case 42: fprintf(stdout,_(" (info \"Network busy\")"));break;
4591       case 47: fprintf(stdout,_(" (info \"Error in connection\")"));break;
4592       case 50: fprintf(stdout,_(" (info \"Check operator services\")"));break;       case 76: fprintf(stdout,_(" (info \"Check operator services\")"));break;
4593       case 111: fprintf(stdout,_(" (info \"Error in connection\")"));break;
4594     }
4595       
4596     fprintf(stdout,_("\n   For more details with errors see netmonitor manual (test 39) on www.marcin-wiacek.topnet.pl"));
4597     fprintf(stdout,_("\n   If know their meaning, GSM specs decribing them, contact with me on marcin-wiacek@topnet.pl. THX\n"));
4598 #endif /* DEBUG */
4599
4600     CurrentIncomingCall[0] = ' ';
4601     if (CurrentCallPassup) CurrentCallPassup(' ');
4602
4603     break;
4604
4605   /* Incoming call alert */
4606   case 0x05:
4607
4608 #ifdef DEBUG
4609     fprintf(stdout, _("Message: Incoming call alert:\n"));
4610
4611     /* We can have more then one call ringing - we can distinguish between
4612        them */
4613
4614     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4615     fprintf(stdout, _("   Number: "));
4616
4617     count=MessageBuffer[6];
4618
4619     for (tmp=0; tmp <count; tmp++)
4620       fprintf(stdout, "%c", MessageBuffer[7+tmp]);
4621
4622     fprintf(stdout, "\n");
4623
4624     fprintf(stdout, _("   Name: "));
4625
4626     for (tmp=0; tmp <MessageBuffer[7+count]; tmp++)
4627       fprintf(stdout, "%c", MessageBuffer[8+count+tmp]);
4628
4629     fprintf(stdout, "\n");
4630 #endif /* DEBUG */
4631
4632     count=MessageBuffer[6];
4633
4634     CurrentIncomingCall[0] = 0;
4635     for (tmp=0; tmp <count; tmp++)
4636       sprintf(CurrentIncomingCall, "%s%c", CurrentIncomingCall, MessageBuffer[7+tmp]);
4637
4638     break;
4639
4640   /* Call answered. Probably your girlfriend...*/
4641   case 0x07:
4642
4643 #ifdef DEBUG
4644     fprintf(stdout, _("Message: Call answered.\n"));
4645     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4646 #endif /* DEBUG */
4647
4648     break;
4649
4650   /* Call ended. Girlfriend is girlfriend, but time is money :-) */
4651   case 0x09:
4652
4653 #ifdef DEBUG
4654     fprintf(stdout, _("Message: Call ended by your phone.\n"));
4655     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4656 #endif /* DEBUG */
4657
4658     break;
4659
4660   /* This message has been seen with the message of subtype 0x09
4661      after I hang the call.
4662
4663   Msg Destination: PC
4664   Msg Source: Phone
4665   Msg Type: 01 
4666   Msg Unknown: 00
4667   Msg Len: 08
4668   Phone: [01 ][08 ][00 ][0a ][04 ][87 ][01 ][42B][1a ][c2 ]
4669
4670   What is the meaning of 87? Can you spell some magic light into
4671   this issue?
4672
4673   */
4674
4675   /* Probably means call over - CK */
4676   case 0x0a:
4677
4678 #ifdef DEBUG
4679     fprintf(stdout, _("Message: Call message, type 0x0a:"));
4680     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4681     fprintf(stdout, _("   Exact meaning not known yet, sorry :-(\n"));
4682 #endif /* DEBUG */
4683
4684     CurrentIncomingCall[0] = ' ';
4685     if (CurrentCallPassup) CurrentCallPassup(' ');
4686
4687     break;
4688
4689   case 0x40:
4690
4691 #ifdef DEBUG
4692       fprintf(stdout, _("Message: Answer for send DTMF or dial voice command\n"));
4693 #endif
4694
4695     if (CurrentSendDTMFError!=GE_NONE) CurrentSendDTMFError=GE_NONE;
4696
4697     if (CurrentDialVoiceError!=GE_NONE) CurrentDialVoiceError=GE_NONE;
4698
4699     break;
4700      
4701   default:
4702
4703 #ifdef DEBUG
4704     fprintf(stdout, _("Message: Unknown message of type 0x01\n"));
4705 #endif /* DEBUG */
4706     AppendLogText("Unknown msg\n",false);
4707
4708     break;      /* Visual C Don't like empty cases */
4709   }
4710 }
4711
4712 void N6110_Dispatch0x03Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4713
4714   int tmp, count;
4715     
4716   switch (MessageBuffer[3]) {
4717
4718   case 0x04:
4719
4720     /* AFAIK, this frame isn't used anywhere - it's rather for testing :-) */
4721     /* If you want see, if it works with your phone make something like that: */
4722
4723     /* unsigned char connect5[] = {N6110_FRAME_HEADER, 0x03}; */
4724     /* Protocol->SendMessage(4, 0x04, connect5); */
4725
4726     /*                                        Marcin-Wiacek@TopNet.PL */
4727     
4728 #ifdef WIN32
4729     sprintf(Current_IMEI, "%s", MessageBuffer+5);
4730     sprintf(Current_Model, "%s", MessageBuffer+21);
4731     sprintf(Current_Revision, "SW%s, HW%s", MessageBuffer+41, MessageBuffer+35);
4732 #else
4733     snprintf(Current_IMEI, GSM_MAX_IMEI_LENGTH, "%s", MessageBuffer+5);
4734     snprintf(Current_Model, GSM_MAX_MODEL_LENGTH, "%s", MessageBuffer+21);
4735     snprintf(Current_Revision, GSM_MAX_REVISION_LENGTH, "SW%s, HW%s", MessageBuffer+41, MessageBuffer+35);
4736 #endif
4737
4738 #ifdef DEBUG
4739     fprintf(stdout, _("Message: Mobile phone identification received:\n"));
4740     fprintf(stdout, _("   IMEI: %s\n"), Current_IMEI);
4741     fprintf(stdout, _("   Model: %s\n"), Current_Model);
4742     fprintf(stdout, _("   Production Code: %s\n"), MessageBuffer+27);
4743     fprintf(stdout, _("   HW: %s\n"), MessageBuffer+35);
4744     fprintf(stdout, _("   Firmware: %s\n"), MessageBuffer+41);
4745 #endif /* DEBUG */
4746
4747     break;
4748
4749   /* Get group data */    
4750   /* [ID],[name_len],[name].,[ringtone],[graphicon],[lenhi],[lenlo],[bitmap] */
4751   case 0x11:   
4752  
4753     if (CurrentGetBitmap!=NULL) {
4754       if (CurrentGetBitmap->number==MessageBuffer[4]) {
4755         count=MessageBuffer[5];
4756         memcpy(CurrentGetBitmap->text,MessageBuffer+6,count);
4757         CurrentGetBitmap->text[count]=0;
4758
4759 #ifdef DEBUG    
4760         fprintf(stdout, _("Message: Caller group datas\n"));
4761         fprintf(stdout, _("Caller group name: %s\n"),CurrentGetBitmap->text);
4762 #endif /* DEBUG */
4763
4764         count+=6;
4765
4766         CurrentGetBitmap->ringtone=MessageBuffer[count++];
4767 #ifdef DEBUG    
4768         fprintf(stdout, _("Caller group ringtone ID: %i"),CurrentGetBitmap->ringtone);
4769         if (CurrentGetBitmap->ringtone==16) fprintf(stdout,_(" (default)"));
4770         fprintf(stdout,_("\n"));
4771 #endif /* DEBUG */
4772
4773         CurrentGetBitmap->enabled=(MessageBuffer[count++]==1);
4774 #ifdef DEBUG    
4775         fprintf(stdout, _("Caller group logo "));
4776         if (CurrentGetBitmap->enabled)
4777           fprintf(stdout, _("enabled \n"));
4778         else
4779           fprintf(stdout, _("disabled \n"));
4780 #endif /* DEBUG */      
4781
4782         CurrentGetBitmap->size=MessageBuffer[count++]<<8;
4783         CurrentGetBitmap->size+=MessageBuffer[count++];
4784 #ifdef DEBUG    
4785         fprintf(stdout, _("Bitmap size=%i\n"),CurrentGetBitmap->size);
4786 #endif /* DEBUG */
4787
4788         count++;
4789         CurrentGetBitmap->width=MessageBuffer[count++];
4790         CurrentGetBitmap->height=MessageBuffer[count++];
4791         count++;
4792         tmp=CurrentGetBitmap->height*CurrentGetBitmap->width/8;
4793         if (CurrentGetBitmap->size>tmp) CurrentGetBitmap->size=tmp;
4794         memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count,CurrentGetBitmap->size);
4795         CurrentGetBitmapError=GE_NONE;
4796       } else {
4797 #ifdef DEBUG    
4798         fprintf(stdout, _("Message: Caller group datas received, but group number does not match (%i is not %i)\n"),MessageBuffer[4],CurrentGetBitmap->number);
4799 #endif
4800       }
4801     } else {
4802 #ifdef DEBUG
4803       fprintf(stdout, _("Message: Caller group data received but not requested!\n"));
4804 #endif
4805     }
4806     break;
4807
4808   /* Get group data error */
4809   case 0x12:   
4810       
4811     CurrentGetBitmapError=GE_UNKNOWN;   
4812 #ifdef DEBUG
4813     fprintf(stdout, _("Message: Error attempting to get caller group data.\n"));
4814 #endif   
4815     break;
4816
4817   /* Set group data OK */      
4818   case 0x14:   
4819       
4820     CurrentSetBitmapError=GE_NONE;      
4821 #ifdef DEBUG
4822     fprintf(stdout, _("Message: Caller group data set correctly.\n"));
4823 #endif
4824     break;
4825
4826   /* Set group data error */
4827   case 0x15:   
4828       
4829     CurrentSetBitmapError=GE_UNKNOWN;      
4830 #ifdef DEBUG
4831     fprintf(stdout, _("Message: Error attempting to set caller group data\n"));
4832 #endif
4833     break;  
4834   
4835   default:
4836
4837 #ifdef DEBUG
4838     fprintf(stdout, _("Message: Unknown message of type 0x03\n"));
4839 #endif /* DEBUG */
4840     AppendLogText("Unknown msg\n",false);
4841
4842     break;      /* Visual C Don't like empty cases */
4843   }
4844 }
4845
4846 void N6110_Dispatch0x05Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4847
4848   int tmp, count, length;
4849   bool issupported;
4850
4851 #ifdef DEBUG
4852   int i;
4853 #endif
4854
4855   switch (MessageBuffer[3]) {
4856
4857   /* Startup Logo */
4858   case 0x17:  
4859
4860 #ifdef DEBUG
4861     fprintf(stdout, _("Message: Startup Logo, welcome note and dealer welcome note received.\n"));
4862 #endif
4863
4864     if (CurrentGetBitmap!=NULL) {
4865        
4866       issupported=false;
4867        
4868       count=5;
4869        
4870       for (tmp=0;tmp<MessageBuffer[4];tmp++){
4871         switch (MessageBuffer[count++]) {
4872         case 0x01:
4873           if (CurrentGetBitmap->type==GSM_StartupLogo) {
4874             CurrentGetBitmap->height=MessageBuffer[count++];
4875             CurrentGetBitmap->width=MessageBuffer[count++];
4876             CurrentGetBitmap->size=CurrentGetBitmap->height*CurrentGetBitmap->width/8;
4877             length=CurrentGetBitmap->size;
4878             memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count,length);
4879           } else {
4880             length=MessageBuffer[count++];
4881             length=length*MessageBuffer[count++]/8;
4882           }
4883           count+=length;
4884 #ifdef DEBUG
4885           fprintf(stdout, _("Startup logo supported - "));
4886           if (length!=0) { fprintf(stdout, _("currently set\n"));   }
4887                     else { fprintf(stdout, _("currently empty\n")); }
4888 #endif
4889           if (CurrentGetBitmap->type==GSM_StartupLogo) issupported=true;
4890           break;
4891         case 0x02:
4892           length=MessageBuffer[count];
4893           if (CurrentGetBitmap->type==GSM_WelcomeNoteText) {
4894             memcpy(CurrentGetBitmap->text,MessageBuffer+count+1,length);
4895             CurrentGetBitmap->text[length]=0;
4896           }
4897 #ifdef DEBUG
4898           fprintf(stdout, _("Startup Text supported - "));
4899           if (length!=0)
4900           {
4901             fprintf(stdout, _("currently set to \""));
4902             for (i=0;i<length;i++) fprintf(stdout, _("%c"),MessageBuffer[count+1+i]);
4903             fprintf(stdout, _("\"\n"));
4904           } else {
4905             fprintf(stdout, _("currently empty\n"));
4906           }
4907 #endif
4908           count+=length+1;
4909           if (CurrentGetBitmap->type==GSM_WelcomeNoteText) issupported=true;
4910           break;
4911         case 0x03:
4912           length=MessageBuffer[count];
4913           if (CurrentGetBitmap->type==GSM_DealerNoteText) {
4914             memcpy(CurrentGetBitmap->text,MessageBuffer+count+1,length);
4915             CurrentGetBitmap->text[length]=0;
4916           }
4917 #ifdef DEBUG
4918           fprintf(stdout, _("Dealer Welcome supported - "));
4919           if (length!=0)
4920           {
4921             fprintf(stdout, _("currently set to \""));
4922             for (i=0;i<length;i++) fprintf(stdout, _("%c"),MessageBuffer[count+1+i]);
4923             fprintf(stdout, _("\"\n"));
4924           } else {
4925             fprintf(stdout, _("currently empty\n"));
4926           }
4927 #endif
4928           count+=length+1;
4929           if (CurrentGetBitmap->type==GSM_DealerNoteText) issupported=true;
4930           break;
4931         }
4932       }
4933       if (issupported) CurrentGetBitmapError=GE_NONE;
4934                   else CurrentGetBitmapError=GE_NOTSUPPORTED;
4935     } else {
4936 #ifdef DEBUG
4937       fprintf(stdout, _("Message: Startup logo received but not requested!\n"));
4938 #endif
4939     }
4940     break;
4941
4942   /* Set startup OK */
4943   case 0x19:   
4944     
4945     CurrentSetBitmapError=GE_NONE;    
4946 #ifdef DEBUG
4947     fprintf(stdout, _("Message: Startup logo, welcome note or dealer welcome note correctly set.\n"));
4948 #endif  
4949     break;      
4950
4951   /* Set Operator Logo OK */
4952   case 0x31:   
4953       
4954 #ifdef DEBUG
4955     fprintf(stdout, _("Message: Operator logo correctly set.\n"));
4956 #endif  
4957
4958     CurrentSetBitmapError=GE_NONE;      
4959     break;
4960
4961   /* Set Operator Logo Error */      
4962   case 0x32:  
4963       
4964 #ifdef DEBUG
4965     fprintf(stdout, _("Message: Error setting operator logo!\n"));
4966 #endif
4967
4968     CurrentSetBitmapError=GE_UNKNOWN;        
4969     break;
4970
4971   /* Operator Logo */
4972   /* [location],[netcode x 3],[lenhi],[lenlo],[bitmap] */ 
4973   case 0x34:
4974  
4975     if (CurrentGetBitmap!=NULL) {
4976
4977       count=5;  /* Location ignored. */
4978
4979       DecodeNetworkCode(MessageBuffer+count, CurrentGetBitmap->netcode);
4980       count=count+3;
4981
4982 #ifdef DEBUG
4983       fprintf(stdout, _("Message: Operator Logo for %s (%s) network received.\n"),
4984                            CurrentGetBitmap->netcode,
4985                            GSM_GetNetworkName(CurrentGetBitmap->netcode));
4986 #endif  
4987
4988       CurrentGetBitmap->size=MessageBuffer[count++]<<8;
4989       CurrentGetBitmap->size+=MessageBuffer[count++];
4990       count++;
4991       CurrentGetBitmap->width=MessageBuffer[count++];
4992       CurrentGetBitmap->height=MessageBuffer[count++];
4993       count++;
4994       tmp=CurrentGetBitmap->height*CurrentGetBitmap->width/8;
4995       if (CurrentGetBitmap->size>tmp) CurrentGetBitmap->size=tmp;
4996       memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count,CurrentGetBitmap->size);
4997       CurrentGetBitmapError=GE_NONE;
4998     } else {
4999 #ifdef DEBUG
5000       fprintf(stdout, _("Message: Operator logo received but not requested!\n"));
5001 #endif
5002     }
5003       
5004     break;
5005
5006   /* Get op logo error */      
5007   case 0x35:
5008      
5009 #ifdef DEBUG
5010     fprintf(stdout, _("Message: Error getting operator logo!\n"));
5011 #endif  
5012     CurrentGetBitmapError=GE_UNKNOWN; 
5013     break;
5014
5015   default:
5016
5017 #ifdef DEBUG
5018     fprintf(stdout, _("Message: Unknown message of type 0x05\n"));
5019 #endif /* DEBUG */
5020     AppendLogText("Unknown msg\n",false);
5021
5022     break;
5023   }
5024 }
5025
5026 void N6110_Dispatch0x06Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5027
5028   int tmp;
5029   unsigned char output[160];
5030
5031 #ifdef DEBUG
5032   int i;
5033 #endif
5034     
5035   switch (MessageBuffer[3]) {
5036
5037   case 0x05:
5038
5039     /* MessageBuffer[3] = 0x05
5040        MessageBuffer[4] = 0x00
5041        MessageBuffer[5] = 0x0f
5042        MessageBuffer[6] = 0x03
5043        MessageBuffer[7] = length of packed message
5044
5045        This is all I have seen - Gerry Anderson */
5046
5047     tmp=GSM_UnpackEightBitsToSeven(0, 82, 82, MessageBuffer+8, output);
5048
5049 #ifdef DEBUG
5050
5051     fprintf(stdout, _("Message from Network operator: "));
5052
5053     for (i=0; i<tmp; i++)
5054        fprintf(stdout, "%c", DecodeWithDefaultAlphabet(output[i]));
5055
5056     fprintf(stdout, "\n");
5057
5058 #endif /* DEBUG */
5059
5060     break;
5061
5062   default:
5063
5064 #ifdef DEBUG
5065     fprintf(stdout, _("Message: Unknown message of type 0x06\n"));
5066 #endif /* DEBUG */
5067     AppendLogText("Unknown msg\n",false);
5068
5069     break;
5070   }
5071 }
5072
5073 void N6110_Dispatch0x09Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5074     
5075   switch (MessageBuffer[3]) {
5076     
5077   case 0x80:    
5078 #ifdef DEBUG
5079     fprintf(stdout, _("Message: SIM card login\n"));
5080 #endif
5081     break;
5082
5083   case 0x81:    
5084 #ifdef DEBUG
5085     fprintf(stdout, _("Message: SIM card logout\n"));
5086 #endif
5087     break;
5088       
5089   default:
5090 #ifdef DEBUG
5091     fprintf(stdout, _("Unknown message of type 0x09.\n"));      
5092 #endif
5093     AppendLogText("Unknown msg\n",false);
5094     break;
5095   }
5096 }
5097
5098 void N6110_Dispatch0x13Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5099
5100   switch(MessageBuffer[3]) {
5101     
5102   case 0x6a:
5103
5104 #ifdef DEBUG
5105     fprintf(stdout, _("Message: Calendar Alarm active\n"));
5106     fprintf(stdout, _("   Item number: %d\n"), MessageBuffer[4]);
5107 #endif /* DEBUG */
5108
5109   default:
5110 #ifdef DEBUG
5111     fprintf(stdout, _("Unknown message of type 0x13.\n"));      
5112 #endif
5113     AppendLogText("Unknown msg\n",false);
5114     break;
5115   }
5116 }
5117
5118 void N6110_Dispatch0x40Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5119
5120   int i;
5121   
5122   switch(MessageBuffer[2]) {
5123
5124   case 0x02:
5125
5126 #ifdef DEBUG
5127     fprintf(stdout, _("Message: ACK for simlock opening part 1\n"));
5128 #endif /* DEBUG */
5129     
5130     CurrentMagicError=GE_NONE;
5131     break;
5132     
5133   case 0x7c:
5134
5135 #ifdef DEBUG
5136     fprintf(stdout, _("Message: Answer for call commands.\n"));
5137 #endif
5138     
5139     CurrentDialVoiceError=GE_NONE;      
5140     break;
5141       
5142   case 0x81:
5143
5144 #ifdef DEBUG
5145     fprintf(stdout, _("Message: ACK for simlock opening part 2\n"));
5146 #endif /* DEBUG */
5147     
5148     CurrentMagicError=GE_NONE;
5149     break;
5150
5151   case 0x82:
5152
5153 #ifdef DEBUG
5154       fprintf(stdout, _("Message: ACK for simlock closing\n"));
5155 #endif /* DEBUG */
5156     
5157     CurrentMagicError=GE_NONE;
5158     break;
5159
5160   case 0xd4:
5161
5162     switch (MessageBuffer[5]) {
5163       case 0xa0:
5164 #ifdef DEBUG
5165         fprintf(stdout,_("Message: EEPROM contest received\n"));
5166 #endif
5167
5168         if (MessageBuffer[8]!=0x00) {
5169           for (i=9;i<MessageLength;i++) {
5170             fprintf(stdout,_("%c"), MessageBuffer[i]);
5171         }
5172
5173         CurrentMagicError=GE_NONE;
5174       }
5175       
5176       break;
5177     }
5178       
5179 #ifdef DEBUG
5180     fprintf(stdout, _("Unknown message of type 0x40.\n"));
5181 #endif /* DEBUG */
5182     AppendLogText("Unknown msg\n",false);      
5183     break;
5184
5185   case 0xcf:
5186
5187     N6110_DisplayTestsInfo(MessageBuffer);
5188     break;
5189       
5190   default:
5191
5192 #ifdef DEBUG
5193     fprintf(stdout, _("Unknown message of type 0x40.\n"));
5194 #endif /* DEBUG */
5195     AppendLogText("Unknown msg\n",false);
5196     break;      /* Visual C Don't like empty cases */
5197   }
5198 }
5199
5200 void N6110_Dispatch0x47Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5201
5202   int count;
5203   
5204   switch(MessageBuffer[3]) {
5205     
5206   case 0x02:
5207
5208     count=5;
5209     
5210     if (MessageBuffer[5]!=0) {
5211       strcpy(CurrentGetBitmap->Sender,GSM_UnpackSemiOctetNumber(MessageBuffer+5,true));
5212
5213       while (MessageBuffer[count]!=0) {
5214         count++;
5215       }
5216
5217       count++;
5218     } else {
5219       strcpy(CurrentGetBitmap->Sender,"\0");
5220
5221       count+=3;
5222     }
5223
5224     memcpy(CurrentGetBitmap->text,MessageBuffer+count+1,MessageBuffer[count]);
5225     CurrentGetBitmap->text[MessageBuffer[count]]=0;
5226
5227     if (MessageBuffer[count]!=0)
5228       count+=MessageBuffer[count];
5229
5230     count++;
5231
5232 #ifdef DEBUG
5233     fprintf(stdout,_("Picture Image received, text \"%s\", sender %s\n"),CurrentGetBitmap->text,CurrentGetBitmap->Sender);
5234 #endif
5235
5236     CurrentGetBitmap->width=MessageBuffer[count+1];
5237     CurrentGetBitmap->height=MessageBuffer[count+2]; 
5238     CurrentGetBitmap->size=CurrentGetBitmap->height*CurrentGetBitmap->width/8;
5239       
5240     memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count+4,CurrentGetBitmap->size);
5241       
5242     CurrentGetBitmapError=GE_NONE;
5243     break;
5244
5245   case 0x04:
5246
5247 #ifdef DEBUG
5248     fprintf(stdout,_("Getting or setting Picture Image - OK\n"));
5249 #endif
5250     CurrentSetBitmapError=GE_NONE;
5251     CurrentGetBitmapError=GE_NONE;
5252     break;      
5253
5254   case 0x05:
5255
5256 #ifdef DEBUG
5257     fprintf(stdout,_("Setting Picture Image - invalid location or other error\n"));
5258 #endif
5259     CurrentSetBitmapError=GE_UNKNOWN;
5260     break;      
5261
5262   case 0x06:
5263
5264 #ifdef DEBUG
5265     fprintf(stdout,_("Getting Picture Image - invalid location or other error\n"));
5266 #endif
5267     CurrentGetBitmapError=GE_UNKNOWN;
5268     break;      
5269
5270   default:
5271
5272 #ifdef DEBUG
5273     fprintf(stdout, _("Unknown message of type 0x47.\n"));
5274 #endif /* DEBUG */
5275     AppendLogText("Unknown msg\n",false);
5276     break;      /* Visual C Don't like empty cases */
5277   }
5278 }
5279
5280 void N6110_DispatchACKMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5281   char buffer[50];
5282   
5283   sprintf(buffer,"Received ACK %02x %02x\n",MessageBuffer[0],MessageBuffer[1]);
5284   AppendLog(buffer,strlen(buffer),false);
5285
5286 #ifdef DEBUG
5287   fprintf(stdout, _("[Received Ack of type %02x, seq: %2x]\n"), MessageBuffer[0],
5288                                                                 MessageBuffer[1]);
5289 #endif /* DEBUG */
5290   
5291   CurrentLinkOK = true;
5292 }
5293
5294 void N6110_Dispatch0xD0Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5295    
5296 #ifdef DEBUG
5297   fprintf(stdout, _("Message: The phone is powered on - seq 1.\n"));
5298 #endif /* DEBUG */
5299
5300 }
5301
5302 /* This function is used for parsing the RLP frame into fields. */
5303 void N6110_RX_HandleRLPMessage(u8 *MessageBuffer)
5304 {
5305
5306   RLP_F96Frame frame;
5307   int count;
5308   int valid = true;
5309
5310   /* We do not need RLP frame parsing to be done when we do not have callback
5311      specified. */
5312   if (CurrentRLP_RXCallback == NULL)
5313     exit;
5314     
5315   /* Anybody know the official meaning of the first two bytes?
5316      Nokia 6150 sends junk frames starting D9 01, and real frames starting
5317      D9 00. We'd drop the junk frames anyway because the FCS is bad, but
5318      it's tidier to do it here. We still need to call the callback function
5319      to give it a chance to handle timeouts and/or transmit a frame */
5320   if (MessageBuffer[0] == 0xd9 && MessageBuffer[1] == 0x01)
5321     valid = false;
5322
5323   /* Nokia uses 240 bit frame size of RLP frames as per GSM 04.22
5324      specification, so Header consists of 16 bits (2 bytes). See section 4.1
5325      of the specification. */
5326     
5327   frame.Header[0] = MessageBuffer[2];
5328   frame.Header[1] = MessageBuffer[3];
5329
5330   /* Next 200 bits (25 bytes) contain the Information. We store the
5331      information in the Data array. */
5332
5333   for (count = 0; count < 25; count ++)
5334     frame.Data[count] = MessageBuffer[4 + count];
5335
5336   /* The last 24 bits (3 bytes) contain FCS. */
5337
5338   frame.FCS[0] = MessageBuffer[29];
5339   frame.FCS[1] = MessageBuffer[30];
5340   frame.FCS[2] = MessageBuffer[31];
5341
5342   /* Here we pass the frame down in the input stream. */
5343   CurrentRLP_RXCallback(valid ? &frame : NULL);
5344 }
5345
5346 void N6110_Dispatch0xF4Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5347
5348 #ifdef DEBUG
5349   fprintf(stdout, _("Message: The phone is powered on - seq 2.\n"));
5350 #endif /* DEBUG */
5351
5352 }
5353
5354 void N6110_ReplyIncomingSMS(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5355
5356   GSM_SMSMessage NullSMS;
5357
5358   switch (MessageBuffer[6]) {
5359
5360     case 0x00: NullSMS.Type = GST_SMS; NullSMS.folder = GST_INBOX; break;
5361     case 0x01: NullSMS.Type = GST_DR;  NullSMS.folder = GST_INBOX; break;
5362
5363     /* Is it possible ? */
5364     case 0x02: NullSMS.Type = GST_SMS; NullSMS.folder = GST_OUTBOX; break;      
5365     default:   NullSMS.Type = GST_UN;                               break;
5366   }
5367
5368 #ifdef DEBUG
5369   if (NullSMS.Type == GST_DR)
5370     fprintf(stdout, _("Message: SMS Message (Report) Received\n"));
5371   else 
5372     fprintf(stdout, _("Message: SMS Message Received\n"));  
5373 #endif /* DEBUG */
5374
5375   GSM_DecodeNokiaSMSFrame(&NullSMS, MessageBuffer+7, MessageLength-7);
5376
5377 #ifdef DEBUG
5378   fprintf(stdout, _("\n"));      
5379 #endif /* DEBUG */
5380 }
5381
5382 void N6110_DispatchMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5383
5384   bool unknown=false;
5385
5386   /* Switch on the basis of the message type byte */
5387   switch (MessageType) {
5388           
5389   /* Call information */
5390   case 0x01:
5391
5392     N6110_Dispatch0x01Message(MessageLength, MessageBuffer, MessageType);
5393     break;
5394
5395   /* SMS handling */
5396   case 0x02:
5397     switch (MessageBuffer[3]) {
5398       case 0x02:
5399       case 0x03:N6110_ReplySendSMSMessage(MessageLength,MessageBuffer,MessageType);break;
5400       case 0x10:N6110_ReplyIncomingSMS(MessageLength,MessageBuffer,MessageType);break;
5401       case 0x21:N6110_ReplySetCellBroadcast(MessageLength, MessageBuffer, MessageType);break;
5402       case 0x23:N6110_ReplyReadCellBroadcast(MessageLength, MessageBuffer, MessageType);break;
5403       case 0x31:N6110_ReplySetSMSCenter(MessageLength,MessageBuffer,MessageType);break;
5404       case 0x34:
5405       case 0x35:N6110_ReplyGetSMSCenter(MessageLength,MessageBuffer,MessageType);break;
5406       default  :unknown=true;break;
5407     }
5408     break;
5409
5410   /* Phonebook handling */
5411   case 0x03:
5412     switch (MessageBuffer[3]) {
5413       case 0x02:
5414       case 0x03:N6110_ReplyGetMemoryLocation(MessageLength,MessageBuffer,MessageType);break;
5415       case 0x05:
5416       case 0x06:N6110_ReplyWritePhonebookLocation(MessageLength,MessageBuffer,MessageType);break;
5417       case 0x08:
5418       case 0x09:N6110_ReplyGetMemoryStatus(MessageLength,MessageBuffer,MessageType);break;
5419       case 0x17:
5420       case 0x18:N6110_ReplyGetSpeedDial(MessageLength,MessageBuffer,MessageType);break;
5421       case 0x1a:
5422       case 0x1b:N6110_ReplySetSpeedDial(MessageLength,MessageBuffer,MessageType);break;
5423       default  :N6110_Dispatch0x03Message(MessageLength,MessageBuffer,MessageType);break;
5424     }
5425     break;
5426
5427   /* Phone status */     
5428   case 0x04:
5429     switch (MessageBuffer[3]) {
5430       case 0x02:N6110_ReplyRFBatteryLevel(MessageLength,MessageBuffer,MessageType);break;
5431       default  :unknown=true;break;
5432     }
5433     break;
5434       
5435   /* Startup Logo, Operator Logo and Profiles. */
5436   case 0x05:
5437     switch (MessageBuffer[3]) {
5438       case 0x11:N6110_ReplySetProfile    (MessageLength,MessageBuffer,MessageType);break;
5439       case 0x14:N6110_ReplyGetProfile    (MessageLength,MessageBuffer,MessageType);break;
5440       case 0x1b:N6110_ReplyGetProfile    (MessageLength,MessageBuffer,MessageType);break;
5441       case 0x1d:N6110_ReplySetProfile    (MessageLength,MessageBuffer,MessageType);break;
5442       case 0x37:N6110_ReplySetRingtone   (MessageLength,MessageBuffer,MessageType);break;
5443       case 0x38:N6110_ReplySetRingtone   (MessageLength,MessageBuffer,MessageType);break;
5444       default  :N6110_Dispatch0x05Message(MessageLength,MessageBuffer,MessageType);break;
5445     }
5446     break;
5447
5448   /* Network Operator Message to handset -> Gerry Anderson & prepaid info */
5449   /* Call diverts */
5450   case 0x06:
5451     switch (MessageBuffer[3]) {
5452       case 0x02:
5453       case 0x03:N6110_ReplyCallDivert    (MessageLength,MessageBuffer,MessageType);break;
5454       default  :N6110_Dispatch0x06Message(MessageLength,MessageBuffer,MessageType);break;
5455     }
5456     break;
5457
5458   /* Security code requests */
5459   case 0x08:
5460     switch (MessageBuffer[3]) {
5461       case 0x08:N6110_ReplyGetSecurityCodeStatus(MessageLength,MessageBuffer,MessageType);break;
5462       case 0x0b:N6110_ReplyEnterSecurityCode    (MessageLength,MessageBuffer,MessageType);break;
5463       default  :N6110_ReplyEnterSecurityCode    (MessageLength,MessageBuffer,MessageType);break;
5464     }
5465     break;
5466
5467   /* SIM login */
5468   case 0x09:
5469
5470     N6110_Dispatch0x09Message(MessageLength, MessageBuffer, MessageType);
5471     break;
5472
5473   /* Network info */
5474   case 0x0a:
5475     switch (MessageBuffer[3]) {
5476       case 0x71:N6110_ReplyGetNetworkInfo(MessageLength,MessageBuffer,MessageType);break;
5477       default  :unknown=true;break;
5478     }
5479     break;
5480
5481   /* Simulating key pressing */
5482   case 0x0c:
5483     switch (MessageBuffer[3]) {
5484       case 0x43:N6110_ReplyPressKey(MessageLength,MessageBuffer,MessageType);break;
5485       default  :unknown=true;break;
5486     }
5487     break;
5488
5489   /* Display */
5490   case 0x0d:
5491     switch (MessageBuffer[3]) {
5492       case 0x50:N6110_ReplyDisplayOutput   (MessageLength,MessageBuffer,MessageType);break;
5493       case 0x52:N6110_ReplyGetDisplayStatus(MessageLength,MessageBuffer,MessageType);break;
5494       case 0x54:N6110_ReplyDisplayOutput   (MessageLength,MessageBuffer,MessageType);break;
5495       default  :unknown=true;break;
5496     }
5497     break;
5498
5499   /* Phone Clock and Alarm */
5500   case 0x11:
5501     switch (MessageBuffer[3]) {
5502       case 0x61:N6110_ReplySetDateTime(MessageLength,MessageBuffer,MessageType);break;
5503       case 0x63:N6110_ReplyGetDateTime(MessageLength,MessageBuffer,MessageType);break;
5504       case 0x6c:N6110_ReplySetAlarm   (MessageLength,MessageBuffer,MessageType);break;
5505       case 0x6e:N6110_ReplyGetAlarm   (MessageLength,MessageBuffer,MessageType);break;
5506       default  :unknown=true;break;
5507     }
5508     break;
5509
5510   /* Calendar notes handling */
5511   case 0x13:
5512     switch (MessageBuffer[3]) {
5513       case 0x65:N6110_ReplyWriteCalendarNote (MessageLength,MessageBuffer,MessageType);break;
5514       case 0x67:N6110_ReplyGetCalendarNote   (MessageLength,MessageBuffer,MessageType);break;
5515       case 0x69:N6110_ReplyDeleteCalendarNote(MessageLength,MessageBuffer,MessageType);break;
5516       default  :N6110_Dispatch0x13Message    (MessageLength,MessageBuffer,MessageType);break;
5517     }
5518     break;
5519
5520   /* SMS Messages */
5521   case 0x14:
5522     switch (MessageBuffer[3]) {
5523       case 0x05:
5524       case 0x06:N6110_ReplySaveSMSMessage  (MessageLength,MessageBuffer,MessageType);break;
5525       case 0x08:
5526       case 0x09:N6110_ReplyGetSMSMessage   (MessageLength,MessageBuffer,MessageType);break;
5527       case 0x0b:N6110_ReplyDeleteSMSMessage(MessageLength,MessageBuffer,MessageType);break;
5528       case 0x37:
5529       case 0x38:N6110_ReplyGetSMSStatus    (MessageLength,MessageBuffer,MessageType);break;
5530       default  :unknown=true;break;
5531     }
5532     break;
5533
5534   /* WAP */
5535   case 0x3f:
5536     switch (MessageBuffer[3]) {
5537       case 0x01:
5538       case 0x02:N7110_ReplyEnableWAPCommands(MessageLength,MessageBuffer,MessageType);break;
5539       case 0x07:
5540       case 0x08:N7110_ReplyGetWAPBookmark   (MessageLength,MessageBuffer,MessageType);break;
5541       case 0x0a:
5542       case 0x0b:N7110_ReplySetWAPBookmark   (MessageLength,MessageBuffer,MessageType);break;
5543       case 0x16:
5544       case 0x17:
5545       case 0x1c:N7110_ReplyGetWAPSettings   (MessageLength,MessageBuffer,MessageType);break;
5546       default  :unknown=true;break;
5547     }
5548     break;
5549
5550   /* Internal phone functions? */
5551   case 0x40:
5552     switch (MessageBuffer[2]) {
5553       case 0x64:N6110_ReplyEnableExtendedCommands  (MessageLength,MessageBuffer,MessageType);break;
5554       case 0x65:N6110_ReplyResetPhoneSettings      (MessageLength,MessageBuffer,MessageType);break;
5555       case 0x66:N6110_ReplyIMEI                    (MessageLength,MessageBuffer,MessageType);break;
5556       case 0x6a:N6110_ReplyGetProductProfileSetting(MessageLength,MessageBuffer,MessageType);break;
5557       case 0x6b:N6110_ReplySetProductProfileSetting(MessageLength,MessageBuffer,MessageType);break;
5558       case 0x6e:N6110_ReplyGetSecurityCode         (MessageLength,MessageBuffer,MessageType);break;
5559       case 0x7e:N6110_ReplyNetmonitor              (MessageLength,MessageBuffer,MessageType);break;
5560       case 0x8a:N6110_ReplySimlockInfo             (MessageLength,MessageBuffer,MessageType);break;
5561       case 0x8b:N6110_ReplySetOperatorName         (MessageLength,MessageBuffer,MessageType);break;
5562       case 0x8c:N6110_ReplyGetOperatorName         (MessageLength,MessageBuffer,MessageType);break;
5563       case 0x8f:N6110_ReplyPlayTone                (MessageLength,MessageBuffer,MessageType);break;
5564       case 0x9e:N6110_ReplyGetBinRingtone          (MessageLength,MessageBuffer,MessageType);break;
5565       case 0xa0:N6110_ReplySetBinRingtone          (MessageLength,MessageBuffer,MessageType);break;
5566       case 0xc8:N6110_ReplyHW                      (MessageLength,MessageBuffer,MessageType);break;
5567       default  :N6110_Dispatch0x40Message          (MessageLength,MessageBuffer,MessageType);break;
5568     }
5569     break;
5570
5571   /* Picture Images */
5572   case 0x47:
5573
5574     N6110_Dispatch0x47Message(MessageLength, MessageBuffer, MessageType);
5575     break;
5576
5577   /* Mobile phone identification */
5578   case 0x64:
5579
5580     N6110_ReplyGetAuthentication(MessageLength, MessageBuffer, MessageType);
5581     break;
5582
5583   /***** Acknowlegment of our frames. *****/
5584   case FBUS_FRTYPE_ACK:
5585
5586     N6110_DispatchACKMessage(MessageLength, MessageBuffer, MessageType);
5587     break;
5588
5589   /***** Power on message. *****/
5590   case 0xd0:
5591
5592     N6110_Dispatch0xD0Message(MessageLength, MessageBuffer, MessageType);
5593     break;
5594
5595   case 0xd2:
5596
5597     N6110_ReplyID(MessageLength, MessageBuffer, MessageType);
5598     break;
5599   
5600   /***** RLP frame received. *****/
5601   case 0xf1:
5602
5603     N6110_RX_HandleRLPMessage(MessageBuffer);
5604     break;
5605
5606   /***** Power on message. *****/
5607   case 0xf4:
5608
5609     N6110_Dispatch0xF4Message(MessageLength, MessageBuffer, MessageType);
5610     break;
5611
5612   /***** Unknown message *****/
5613   /* If you think that you know the exact meaning of other messages - please
5614      let us know. */
5615   default:
5616
5617 #ifdef DEBUG
5618     fprintf(stdout, _("Message: Unknown message type.\n"));
5619 #endif /* DEBUG */
5620     AppendLogText("Unknown msg type\n",false);
5621
5622     unknown=false;
5623     break;
5624
5625   }
5626
5627   if (unknown) {
5628 #ifdef DEBUG
5629     fprintf(stdout, _("Unknown message of type %02x.\n"),MessageType);
5630 #endif
5631     AppendLogText("Unknown msg\n",false);
5632   }
5633 }