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