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