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