datacalls: Disabled sending of the 2nd analog-datacall-request packet
[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 #if 0
2614         usleep(1000000);
2615         if (type != 1) Protocol->SendMessage(26, 0x01, req2);
2616 #endif
2617
2618         return (GE_NONE);
2619 }
2620
2621 #ifndef UCLINUX
2622
2623 GSM_Error N6110_GetIncomingCallNr(char *Number)
2624 {
2625
2626   if (*CurrentIncomingCall != ' ') {
2627     strcpy(Number, CurrentIncomingCall);
2628     return GE_NONE;
2629   }
2630   else
2631     return GE_BUSY;
2632 }
2633
2634 #endif /* UCLINUX */
2635
2636 GSM_Error N6110_CancelCall(void)
2637 {
2638 //  This frame & method works only on 61xx/51xx
2639 //  unsigned char req[] = { N6110_FRAME_HEADER, 0x08, 0x00, 0x85};
2640 //  req[4]=CurrentCallSequenceNumber;
2641 //  Protocol->SendMessage(6, 0x01, req);
2642 //  return GE_NONE;
2643  
2644   GSM_Error error;
2645
2646   unsigned char req[]={0x00,0x01,0x7c,0x03};
2647     
2648   /* Checking */
2649   error=N6110_EnableExtendedCommands(0x01);
2650   if (error!=GE_NONE) return error;
2651
2652   return NULL_SendMessageSequence (20, &CurrentDialVoiceError, 4, 0x40, req);   
2653 }  
2654
2655 #ifndef UCLINUX
2656
2657 void N6110_ReplyEnterSecurityCode(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2658     
2659   switch(MessageBuffer[3]) {
2660
2661   case 0x0b:
2662 #ifdef DEBUG
2663     fprintf(stdout, _("Message: Security code accepted.\n"));
2664 #endif /* DEBUG */
2665     CurrentSecurityCodeError = GE_NONE;
2666     break;
2667
2668   default:
2669 #ifdef DEBUG
2670     fprintf(stdout, _("Message: Security code is wrong. You're not my big owner :-)\n"));
2671 #endif /* DEBUG */
2672     CurrentSecurityCodeError = GE_INVALIDSECURITYCODE;
2673   }
2674 }
2675
2676 GSM_Error N6110_EnterSecurityCode(GSM_SecurityCode SecurityCode)
2677 {
2678
2679   unsigned char req[15] = { N6110_FRAME_HEADER,
2680                             0x0a, /* Enter code request. */
2681                             0x00  /* Type of the entered code. */
2682                             };
2683   int i=0;
2684
2685   req[4]=SecurityCode.Type;
2686
2687   for (i=0; i<strlen(SecurityCode.Code);i++)
2688     req[5+i]=SecurityCode.Code[i];
2689
2690   req[5+strlen(SecurityCode.Code)]=0x00;
2691   req[6+strlen(SecurityCode.Code)]=0x00;
2692
2693   return NULL_SendMessageSequence
2694     (20, &CurrentSecurityCodeError, 7+strlen(SecurityCode.Code), 0x08, req);
2695 }
2696
2697 void N6110_ReplyGetSecurityCodeStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2698     
2699   *CurrentSecurityCodeStatus = MessageBuffer[4];
2700
2701 #ifdef DEBUG
2702   fprintf(stdout, _("Message: Security Code status received: "));
2703
2704   switch(*CurrentSecurityCodeStatus) {
2705
2706     case GSCT_SecurityCode: fprintf(stdout, _("waiting for Security Code.\n")); break;
2707     case GSCT_Pin         : fprintf(stdout, _("waiting for PIN.\n")); break;
2708     case GSCT_Pin2        : fprintf(stdout, _("waiting for PIN2.\n")); break;
2709     case GSCT_Puk         : fprintf(stdout, _("waiting for PUK.\n")); break;
2710     case GSCT_Puk2        : fprintf(stdout, _("waiting for PUK2.\n")); break;
2711     case GSCT_None        : fprintf(stdout, _("nothing to enter.\n")); break;
2712     default               : fprintf(stdout, _("Unknown!\n"));
2713   }
2714       
2715 #endif /* DEBUG */
2716
2717   CurrentSecurityCodeError = GE_NONE;
2718 }
2719
2720 GSM_Error N6110_GetSecurityCodeStatus(int *Status)
2721 {
2722
2723   unsigned char req[4] = { N6110_FRAME_HEADER,
2724                            0x07
2725                          };
2726
2727   CurrentSecurityCodeStatus=Status;
2728
2729   return NULL_SendMessageSequence
2730     (20, &CurrentSecurityCodeError, 4, 0x08, req);
2731 }
2732
2733 void N6110_ReplyGetSecurityCode(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2734
2735   int i;
2736   
2737 #ifdef DEBUG
2738   fprintf(stdout, _("Message: Security code received: "));
2739   switch (MessageBuffer[3]) {
2740     case GSCT_SecurityCode: fprintf(stdout, _("Security code"));break;
2741     case GSCT_Pin:  fprintf(stdout, _("PIN"));break;
2742     case GSCT_Pin2: fprintf(stdout, _("PIN2"));break;
2743     case GSCT_Puk:  fprintf(stdout, _("PUK"));break;
2744     case GSCT_Puk2: fprintf(stdout, _("PUK2"));break;
2745     default: fprintf(stdout, _("unknown !"));break;
2746   }
2747   if (MessageBuffer[4]==1) {
2748     fprintf(stdout, _(" allowed, value \""));
2749     if (MessageBuffer[3]==GSCT_SecurityCode) {
2750       for (i=0;i<5;i++) {fprintf(stdout, _("%c"), MessageBuffer[5+i]);}
2751     }
2752     if (MessageBuffer[3]==GSCT_Pin || MessageBuffer[3]==GSCT_Pin2 ||
2753         MessageBuffer[3]==GSCT_Puk || MessageBuffer[3]==GSCT_Puk2) {
2754       for (i=0;i<4;i++) {fprintf(stdout, _("%c"), MessageBuffer[5+i]);}
2755     }
2756     fprintf(stdout, _("\""));
2757   } else {
2758     fprintf(stdout, _(" not allowed"));  
2759   }
2760   fprintf(stdout, _("\n"));  
2761 #endif /* DEBUG */
2762       
2763   if (CurrentSecurityCode->Type==MessageBuffer[3] /* We wanted this code */
2764           && MessageBuffer[4]==1) {                      /* It's allowed */
2765     if (MessageBuffer[3]==GSCT_SecurityCode) {
2766       for (i=0;i<5;i++) {CurrentSecurityCode->Code[i]=MessageBuffer[5+i];}
2767       CurrentSecurityCode->Code[5]=0;
2768     }
2769     if (MessageBuffer[3]==GSCT_Pin || MessageBuffer[3]==GSCT_Pin2 ||
2770         MessageBuffer[3]==GSCT_Puk || MessageBuffer[3]==GSCT_Puk2) {
2771       for (i=0;i<4;i++) {CurrentSecurityCode->Code[i]=MessageBuffer[5+i];}
2772       CurrentSecurityCode->Code[4]=0;
2773     }
2774     CurrentSecurityCodeError=GE_NONE;
2775   } else
2776     CurrentSecurityCodeError=GE_INVALIDSECURITYCODE;
2777 }
2778
2779 GSM_Error N6110_GetSecurityCode(GSM_SecurityCode *SecurityCode)
2780 {
2781
2782   unsigned char req[4] = { 0x00,
2783                            0x01,0x6e, /* Get code request. */
2784                            0x00 };    /* Type of the requested code. */
2785
2786   GSM_Error error;
2787   
2788   error=N6110_EnableExtendedCommands(0x01);
2789   if (error!=GE_NONE) return error;
2790   
2791   req[3]=SecurityCode->Type;
2792
2793   CurrentSecurityCode=SecurityCode;
2794
2795   return NULL_SendMessageSequence
2796     (20, &CurrentSecurityCodeError, 4, 0x40, req);
2797 }
2798
2799 void N6110_ReplyPlayTone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2800
2801 #ifdef DEBUG
2802   fprintf(stdout, _("Message: answer for PlayTone frame\n"));      
2803 #endif
2804       
2805   CurrentPlayToneError=GE_NONE;      
2806 }
2807
2808 GSM_Error N6110_PlayTone(int Herz, u8 Volume)
2809 {
2810   unsigned char req[6] = { 0x00,0x01,0x8f,
2811                            0x00,   /* Volume */
2812                            0x00,   /* HerzLo */
2813                            0x00 }; /* HerzHi */
2814
2815   GSM_Error error;
2816
2817   /* PlayTone wasn't used earlier */
2818   if (CurrentPlayToneError==GE_UNKNOWN) {
2819     if (CurrentConnectionType!=GCT_MBUS)
2820       CurrentDisableKeepAlive=true;
2821
2822     error=N6110_EnableExtendedCommands(0x01);
2823     if (error!=GE_NONE) return error;
2824   }
2825
2826   /* For Herz==255*255 we have silent */  
2827   if (Herz!=255*255) {
2828     req[3]=Volume;
2829
2830     req[5]=Herz%256;
2831     req[4]=Herz/256;
2832   } else {
2833     req[3]=0;
2834
2835     req[5]=0;
2836     req[4]=0;
2837   }
2838
2839 #ifdef WIN32
2840   /* For Herz==255*255 we have silent and additionaly
2841      we wait for phone answer - it's important for MBUS */
2842   if (Herz==255*255) {
2843     error=NULL_SendMessageSequence
2844       (20, &CurrentPlayToneError, 6, 0x40, req);
2845
2846     CurrentPlayToneError=GE_UNKNOWN;
2847     CurrentDisableKeepAlive=false;
2848
2849     if (error!=GE_NONE) return error;
2850   } else {
2851     Protocol->SendMessage(6,0x40,req);
2852   }
2853 #else
2854   error=NULL_SendMessageSequence
2855     (20, &CurrentPlayToneError, 6, 0x40, req);
2856
2857   /* For Herz==255*255 we wait for phone answer - it's important for MBUS */
2858   if (Herz==255*255) {
2859     CurrentPlayToneError=GE_UNKNOWN;
2860     CurrentDisableKeepAlive=false;
2861   }
2862   
2863   if (error!=GE_NONE) return error;
2864
2865 #endif
2866     
2867   return(GE_NONE);
2868 }
2869
2870 void N6110_ReplyGetDateTime(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2871
2872   if (MessageBuffer[4]==0x01) {
2873     DecodeDateTime(MessageBuffer+8, CurrentDateTime);
2874
2875 #ifdef DEBUG
2876     fprintf(stdout, _("Message: Date and time\n"));
2877     fprintf(stdout, _("   Time: %02d:%02d:%02d\n"), CurrentDateTime->Hour, CurrentDateTime->Minute, CurrentDateTime->Second);
2878     fprintf(stdout, _("   Date: %4d/%02d/%02d\n"), CurrentDateTime->Year, CurrentDateTime->Month, CurrentDateTime->Day);
2879 #endif /* DEBUG */
2880
2881     CurrentDateTime->IsSet=true;
2882   } else {
2883
2884 #ifdef DEBUG
2885     fprintf(stdout, _("Message: Date and time not set in phone\n"));
2886 #endif
2887
2888     CurrentDateTime->IsSet=false;
2889   }
2890       
2891   CurrentDateTimeError=GE_NONE;
2892 }
2893
2894 GSM_Error N6110_GetDateTime(GSM_DateTime *date_time)
2895 {
2896   return N6110_PrivGetDateTime(date_time,0x11);
2897 }
2898
2899 GSM_Error N6110_PrivGetDateTime(GSM_DateTime *date_time, int msgtype)
2900 {
2901   unsigned char req[] = {N6110_FRAME_HEADER, 0x62};
2902
2903   CurrentDateTime=date_time;
2904
2905   return NULL_SendMessageSequence
2906     (50, &CurrentDateTimeError, 4, msgtype, req);
2907 }
2908
2909 void N6110_ReplyGetAlarm(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2910
2911 #ifdef DEBUG
2912   fprintf(stdout, _("Message: Alarm\n"));
2913   fprintf(stdout, _("   Alarm: %02d:%02d\n"), MessageBuffer[9], MessageBuffer[10]);
2914   fprintf(stdout, _("   Alarm is %s\n"), (MessageBuffer[8]==2) ? _("on"):_("off"));
2915 #endif /* DEBUG */
2916
2917   CurrentAlarm->Hour=MessageBuffer[9];
2918   CurrentAlarm->Minute=MessageBuffer[10];
2919   CurrentAlarm->Second=0;
2920
2921   CurrentAlarm->IsSet=(MessageBuffer[8]==2);
2922
2923   CurrentAlarmError=GE_NONE;
2924 }
2925
2926 GSM_Error N6110_GetAlarm(int alarm_number, GSM_DateTime *date_time)
2927 {
2928   return N6110_PrivGetAlarm(alarm_number,date_time,0x11);
2929 }
2930
2931 GSM_Error N6110_PrivGetAlarm(int alarm_number, GSM_DateTime *date_time, int msgtype)
2932 {
2933   unsigned char req[] = {N6110_FRAME_HEADER, 0x6d};
2934
2935   CurrentAlarm=date_time;
2936
2937   return NULL_SendMessageSequence
2938     (50, &CurrentAlarmError, 4, msgtype, req);
2939 }
2940
2941 void N6110_ReplyGetSMSCenter(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2942   
2943   switch (MessageBuffer[3]) {
2944
2945   case 0x34:
2946
2947     CurrentMessageCenter->No=MessageBuffer[4];
2948     CurrentMessageCenter->Format=MessageBuffer[6];
2949     CurrentMessageCenter->Validity=MessageBuffer[8];
2950     sprintf(CurrentMessageCenter->Name, "%s", MessageBuffer+33);
2951
2952     sprintf(CurrentMessageCenter->DefaultRecipient, "%s", GSM_UnpackSemiOctetNumber(MessageBuffer+9,false));
2953
2954     sprintf(CurrentMessageCenter->Number, "%s", GSM_UnpackSemiOctetNumber(MessageBuffer+21,false));
2955       
2956 #ifdef DEBUG
2957     fprintf(stdout, _("Message: SMS Center received:\n"));
2958     fprintf(stdout, _("   %d. SMS Center name is %s\n"), CurrentMessageCenter->No, CurrentMessageCenter->Name);
2959     fprintf(stdout, _("   SMS Center number is %s\n"), CurrentMessageCenter->Number);
2960     fprintf(stdout, _("   Default recipient number is %s\n"), CurrentMessageCenter->DefaultRecipient);
2961       
2962     fprintf(stdout, _("   SMS Center message format is "));
2963
2964     switch (CurrentMessageCenter->Format) {
2965
2966       case GSMF_Text  : fprintf(stdout, _("Text"));   break;
2967       case GSMF_Paging: fprintf(stdout, _("Paging")); break;
2968       case GSMF_Fax   : fprintf(stdout, _("Fax"));    break;
2969       case GSMF_Email : fprintf(stdout, _("Email"));  break;
2970       default         : fprintf(stdout, _("Unknown"));
2971     }
2972
2973     fprintf(stdout, "\n");
2974
2975     fprintf(stdout, _("   SMS Center message validity is "));
2976
2977     switch (CurrentMessageCenter->Validity) {
2978
2979       case GSMV_1_Hour  : fprintf(stdout, _("1 hour"));      break;
2980       case GSMV_6_Hours : fprintf(stdout, _("6 hours"));     break;
2981       case GSMV_24_Hours: fprintf(stdout, _("24 hours"));    break;
2982       case GSMV_72_Hours: fprintf(stdout, _("72 hours"));    break;
2983       case GSMV_1_Week  : fprintf(stdout, _("1 week"));      break;
2984       case GSMV_Max_Time: fprintf(stdout, _("Maximum time"));break;
2985       default           : fprintf(stdout, _("Unknown"));
2986     }
2987
2988     fprintf(stdout, "\n");
2989
2990 #endif /* DEBUG */
2991
2992     CurrentMessageCenterError=GE_NONE;
2993
2994     break;
2995
2996   case 0x35:
2997
2998     /* Number of entries depends on SIM card */
2999
3000 #ifdef DEBUG
3001     fprintf(stdout, _("Message: SMS Center error received:\n"));
3002     fprintf(stdout, _("   The request for SMS Center failed.\n"));
3003 #endif /* DEBUG */
3004
3005     /* FIXME: appropriate error. */
3006     CurrentMessageCenterError=GE_INTERNALERROR;
3007
3008     break;  
3009
3010   }
3011 }
3012
3013 /* This function sends to the mobile phone a request for the SMS Center */
3014 GSM_Error N6110_GetSMSCenter(GSM_MessageCenter *MessageCenter)
3015 {
3016   unsigned char req[] = { N6110_FRAME_HEADER, 0x33, 0x64,
3017                           0x00 /* SMS Center Number. */
3018                         };
3019
3020   req[5]=MessageCenter->No;
3021
3022   CurrentMessageCenter=MessageCenter;
3023
3024   return NULL_SendMessageSequence
3025     (50, &CurrentMessageCenterError, 6, 0x02, req);
3026 }
3027
3028 void N6110_ReplySetSMSCenter(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3029
3030 #ifdef DEBUG
3031   fprintf(stdout, _("Message: SMS Center correctly set.\n"));
3032 #endif
3033   CurrentMessageCenterError=GE_NONE;
3034 }
3035
3036 /* This function set the SMS Center profile on the phone. */
3037 GSM_Error N6110_SetSMSCenter(GSM_MessageCenter *MessageCenter)
3038 {
3039   unsigned char req[64] = { N6110_FRAME_HEADER, 0x30, 0x64,
3040                             0x00, /* SMS Center Number. */
3041                             0x00, /* Unknown. */
3042                             0x00, /* SMS Message Format. */
3043                             0x00, /* Unknown. */
3044                             0x00, /* Validity. */
3045                             0,0,0,0,0,0,0,0,0,0,0,0, /* Default recipient number */
3046                             0,0,0,0,0,0,0,0,0,0,0,0 /* Message Center Number. */
3047                             /* Message Center Name. */
3048                           };
3049
3050   req[5]=MessageCenter->No;
3051   req[7]=MessageCenter->Format;
3052   req[9]=MessageCenter->Validity;
3053
3054   req[10]=GSM_PackSemiOctetNumber(MessageCenter->DefaultRecipient, req+11, false);
3055
3056   req[22]=GSM_PackSemiOctetNumber(MessageCenter->Number, req+23, false);
3057
3058   sprintf(req+34, "%s", MessageCenter->Name);
3059
3060   CurrentMessageCenter=MessageCenter;
3061
3062   return NULL_SendMessageSequence
3063     (50, &CurrentMessageCenterError, 35+strlen(MessageCenter->Name), 0x02, req);
3064 }
3065
3066 void N6110_ReplyGetSMSStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3067
3068   switch (MessageBuffer[3]) {
3069
3070   case 0x37:
3071
3072 #ifdef DEBUG
3073     fprintf(stdout, _("Message: SMS Status Received\n"));
3074     fprintf(stdout, _("   The number of messages: %d\n"), MessageBuffer[10]);
3075     fprintf(stdout, _("   Unread messages: %d\n"), MessageBuffer[11]);
3076 #endif /* DEBUG */
3077
3078     CurrentSMSStatus->UnRead = MessageBuffer[11];
3079     CurrentSMSStatus->Number = MessageBuffer[10];
3080     
3081     CurrentSMSStatusError = GE_NONE;
3082     break;
3083
3084   case 0x38:
3085
3086 #ifdef DEBUG
3087     fprintf(stdout, _("Message: SMS Status error, probably not authorized by PIN\n"));
3088 #endif /* DEBUG */
3089
3090     CurrentSMSStatusError = GE_INTERNALERROR;
3091     break;
3092           
3093   }
3094 }
3095
3096 GSM_Error N6110_GetSMSStatus(GSM_SMSStatus *Status)
3097 {
3098   unsigned char req[] = {N6110_FRAME_HEADER, 0x36, 0x64};
3099
3100   CurrentSMSStatus = Status;
3101
3102   return NULL_SendMessageSequence
3103     (10, &CurrentSMSStatusError, 5, 0x14, req);
3104 }
3105
3106 GSM_Error N6110_GetSMSFolders ( GSM_SMSFolders *folders)
3107 {
3108   folders->number=2;
3109
3110   strcpy(folders->Folder[0].Name,"Inbox");
3111   strcpy(folders->Folder[1].Name,"Outbox");
3112   
3113   return GE_NONE;
3114 }
3115
3116 #endif /* UCLINUX */
3117
3118 GSM_Error N6110_GetIMEI(char *imei)
3119 {
3120   if (strlen(Current_IMEI)>0) {
3121     strncpy (imei, Current_IMEI, GSM_MAX_IMEI_LENGTH);
3122     return (GE_NONE);
3123   }
3124   else
3125     return (GE_TRYAGAIN);
3126 }
3127
3128 GSM_Error N6110_GetRevision(char *revision)
3129 {
3130
3131   if (strlen(Current_Revision)>0) {
3132     strncpy (revision, Current_Revision, GSM_MAX_REVISION_LENGTH);
3133     return (GE_NONE);
3134   }
3135   else
3136     return (GE_TRYAGAIN);
3137 }
3138
3139 static GSM_Error N6110_GetModel(char *model)
3140 {
3141   if (strlen(Current_Model)>0) {
3142     strncpy (model, Current_Model, GSM_MAX_MODEL_LENGTH);
3143     return (GE_NONE);
3144   }
3145   else
3146     return (GE_TRYAGAIN);
3147 }
3148
3149 #ifndef UCLINUX
3150
3151 void N6110_ReplySetDateTime(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3152
3153   switch (MessageBuffer[4]) {
3154
3155     case 0x01:
3156 #ifdef DEBUG
3157       fprintf(stdout, _("Message: Date and time set correctly\n"));
3158 #endif /* DEBUG */
3159       CurrentSetDateTimeError=GE_NONE;
3160       break;
3161       
3162     default:
3163 #ifdef DEBUG
3164       fprintf(stdout, _("Message: Date and time setting error\n"));
3165 #endif /* DEBUG */
3166       CurrentSetDateTimeError=GE_INVALIDDATETIME;
3167
3168   }
3169 }
3170
3171 /* Needs SIM card with PIN in phone */
3172 GSM_Error N6110_SetDateTime(GSM_DateTime *date_time)
3173 {
3174   return N6110_PrivSetDateTime(date_time,0x11);
3175 }
3176
3177 /* Needs SIM card with PIN in phone */
3178 GSM_Error N6110_PrivSetDateTime(GSM_DateTime *date_time, int msgtype)
3179 {
3180
3181   unsigned char req[] = { N6110_FRAME_HEADER,
3182                           0x60, /* set-time subtype */
3183                           0x01, 0x01, 0x07, /* unknown */
3184                           0x00, 0x00, /* Year (0x07cf = 1999) */
3185                           0x00, 0x00, /* Month Day */
3186                           0x00, 0x00, /* Hours Minutes */
3187                           0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
3188                         };
3189
3190   EncodeDateTime(req+7, date_time);
3191
3192   return NULL_SendMessageSequence
3193     (20, &CurrentSetDateTimeError, 14, msgtype, req);
3194 }
3195
3196 void N6110_ReplySetAlarm(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3197
3198   switch (MessageBuffer[4]) {
3199
3200     case 0x01:
3201 #ifdef DEBUG
3202       fprintf(stdout, _("Message: Alarm set correctly\n"));
3203 #endif /* DEBUG */
3204       CurrentSetAlarmError=GE_NONE;
3205       break;
3206       
3207     default:
3208 #ifdef DEBUG
3209       fprintf(stdout, _("Message: Alarm setting error\n"));
3210 #endif /* DEBUG */
3211       CurrentSetAlarmError=GE_INVALIDDATETIME;
3212
3213   }
3214 }
3215
3216 /* FIXME: we should also allow to set the alarm off :-) */
3217 GSM_Error N6110_SetAlarm(int alarm_number, GSM_DateTime *date_time)
3218 {
3219   return N6110_PrivSetAlarm(alarm_number,date_time, 0x11);
3220 }
3221
3222 /* FIXME: we should also allow to set the alarm off :-) */
3223 GSM_Error N6110_PrivSetAlarm(int alarm_number, GSM_DateTime *date_time, int msgtype)
3224 {
3225
3226   unsigned char req[] = { N6110_FRAME_HEADER,
3227                           0x6b, /* set-alarm subtype */
3228                           0x01, 0x20, 0x03, /* unknown */
3229                           0x02,       /* should be alarm on/off, but it don't works */
3230                           0x00, 0x00, /* Hours Minutes */
3231                           0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
3232                         };
3233
3234   req[8] = date_time->Hour;
3235   req[9] = date_time->Minute;
3236
3237   return NULL_SendMessageSequence
3238     (50, &CurrentSetAlarmError, 11, msgtype, req);
3239 }
3240
3241 #endif /* UCLINUX */
3242
3243 static void N6110_ReplyGetMemoryLocation(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3244
3245   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
3246   char model[64];
3247
3248   int i, tmp, count;
3249     
3250   switch (MessageBuffer[3]) {
3251
3252   case 0x02:
3253
3254     CurrentPhonebookEntry->Empty = true;
3255
3256     count=MessageBuffer[5];
3257           
3258 #ifdef DEBUG
3259     fprintf(stdout, _("Message: Phonebook entry received:\n"));
3260     fprintf(stdout, _("   Name: "));
3261
3262     for (tmp=0; tmp <count; tmp++)
3263     {
3264       if (MessageBuffer[6+tmp]==1) fprintf(stdout, "%c", '~'); else //enables/disables blinking
3265       if (MessageBuffer[6+tmp]==0) fprintf(stdout, "%c", '`'); else //hides rest ot contents
3266       fprintf(stdout, "%c", MessageBuffer[6+tmp]);
3267     }
3268
3269     fprintf(stdout, "\n");
3270 #endif /* DEBUG */
3271
3272     while (N6110_GetModel(model)  != GE_NONE)
3273       sleep(1);
3274         
3275     if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {//pbk with Unicode
3276 #ifndef UCLINUX
3277       DecodeUnicode (CurrentPhonebookEntry->Name, MessageBuffer+6, count/2);
3278       CurrentPhonebookEntry->Name[count/2] = 0x00;
3279 #else /* UCLINUX */
3280       fprintf(stderr,"FATAL ERROR: DecodeUnicode disabled!\n");
3281       exit(1);
3282 #endif /* UCLINUX */
3283     } else {
3284       memcpy(CurrentPhonebookEntry->Name, MessageBuffer + 6, count);
3285       CurrentPhonebookEntry->Name[count] = 0x00;
3286     }
3287
3288     CurrentPhonebookEntry->Empty = false;
3289
3290     for (tmp=0; tmp <count; tmp++)
3291     {
3292       if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {//pbk with Unicode
3293         /* We check only 1'st, 3'rd, ... char */
3294         if (tmp%2!=0 && MessageBuffer[6+tmp]==1) CurrentPhonebookEntry->Name[tmp/2]='~'; //enables/disables blinking
3295         if (tmp%2!=0 && MessageBuffer[6+tmp]==0) CurrentPhonebookEntry->Name[tmp/2]='`'; //hides rest ot contents
3296       } else {
3297         if (MessageBuffer[6+tmp]==1) CurrentPhonebookEntry->Name[tmp]='~'; //enables/disables blinking
3298         if (MessageBuffer[6+tmp]==0) CurrentPhonebookEntry->Name[tmp]='`'; //hides rest ot contents
3299       }
3300     }
3301
3302     i=7+count;
3303     count=MessageBuffer[6+count];
3304
3305 #ifdef DEBUG
3306     fprintf(stdout, _("   Number: "));
3307
3308     for (tmp=0; tmp <count; tmp++)
3309       fprintf(stdout, "%c", MessageBuffer[i+tmp]);
3310
3311     fprintf(stdout, "\n");
3312 #endif /* DEBUG */
3313
3314     memcpy(CurrentPhonebookEntry->Number, MessageBuffer + i, count);
3315     CurrentPhonebookEntry->Number[count] = 0x00;
3316     CurrentPhonebookEntry->Group = MessageBuffer[i+count];
3317       
3318     /* Phone doesn't have entended phonebook */
3319     CurrentPhonebookEntry->SubEntriesCount = 0;
3320
3321     /* But for these memories data is saved and we can save it using 7110/6210 style */
3322     if (CurrentPhonebookEntry->MemoryType==GMT_DC ||
3323         CurrentPhonebookEntry->MemoryType==GMT_RC ||
3324         CurrentPhonebookEntry->MemoryType==GMT_MC) {
3325         CurrentPhonebookEntry->SubEntriesCount = 1;
3326         CurrentPhonebookEntry->SubEntries[0].EntryType=N7110_ENTRYTYPE_DATE;
3327         CurrentPhonebookEntry->SubEntries[0].NumberType=0;
3328         CurrentPhonebookEntry->SubEntries[0].BlockNumber=1;
3329         DecodeDateTime(MessageBuffer+(i+count+2),&CurrentPhonebookEntry->SubEntries[0].data.Date);
3330
3331 #ifdef DEBUG
3332       fprintf(stdout, _("   Date: "));
3333       fprintf(stdout, "%02u.%02u.%04u\n",
3334           CurrentPhonebookEntry->SubEntries[0].data.Date.Day,
3335           CurrentPhonebookEntry->SubEntries[0].data.Date.Month,
3336           CurrentPhonebookEntry->SubEntries[0].data.Date.Year);
3337       fprintf(stdout, _("   Time: "));
3338       fprintf(stdout, "%02u:%02u:%02u\n",
3339           CurrentPhonebookEntry->SubEntries[0].data.Date.Hour,
3340           CurrentPhonebookEntry->SubEntries[0].data.Date.Minute,
3341           CurrentPhonebookEntry->SubEntries[0].data.Date.Second);
3342 #endif /* DEBUG */
3343
3344       /* These values are set, when date and time unavailable in phone.
3345          Values from 3310 - in other can be different */
3346       if (CurrentPhonebookEntry->SubEntries[0].data.Date.Day==20 &&
3347           CurrentPhonebookEntry->SubEntries[0].data.Date.Month==1 &&
3348           CurrentPhonebookEntry->SubEntries[0].data.Date.Year==2118 &&
3349           CurrentPhonebookEntry->SubEntries[0].data.Date.Hour==3 &&
3350           CurrentPhonebookEntry->SubEntries[0].data.Date.Minute==14 &&
3351           CurrentPhonebookEntry->SubEntries[0].data.Date.Second==7)
3352           CurrentPhonebookEntry->SubEntriesCount = 0;
3353     }
3354
3355     /* Signal no error to calling code. */
3356     CurrentPhonebookError = GE_NONE;
3357
3358     break;
3359
3360   case 0x03:
3361
3362 #ifdef DEBUG
3363     fprintf(stdout, _("Message: Phonebook read entry error received:\n"));
3364 #endif /* DEBUG */
3365
3366     switch (MessageBuffer[4]) {
3367
3368       case 0x7d:
3369 #ifdef DEBUG
3370         fprintf(stdout, _("   Invalid memory type!\n"));
3371 #endif /* DEBUG */
3372         CurrentPhonebookError = GE_INVALIDMEMORYTYPE;
3373         break;
3374
3375       default:
3376 #ifdef DEBUG
3377         fprintf(stdout, _("   Unknown error!\n"));
3378 #endif /* DEBUG */
3379         CurrentPhonebookError = GE_INTERNALERROR;
3380     }
3381
3382     break;
3383
3384   }
3385 }
3386
3387 /* Routine to get specifed phone book location.  Designed to be called by
3388    application.  Will block until location is retrieved or a timeout/error
3389    occurs. */
3390 GSM_Error N6110_GetMemoryLocation(GSM_PhonebookEntry *entry)
3391 {
3392   unsigned char req[] = {N6110_FRAME_HEADER, 0x01, 0x00, 0x00, 0x00};
3393
3394   CurrentPhonebookEntry = entry;
3395
3396   req[4] = N6110_GetMemoryType(entry->MemoryType);
3397   req[5] = entry->Location;
3398
3399   return NULL_SendMessageSequence
3400     (50, &CurrentPhonebookError, 7, 0x03, req);
3401 }
3402
3403 static void N6110_ReplyWritePhonebookLocation(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3404
3405   switch (MessageBuffer[3]) {
3406
3407   case 0x05:
3408
3409 #ifdef DEBUG
3410     fprintf(stdout, _("Message: Phonebook written correctly.\n"));
3411 #endif /* DEBUG */
3412     CurrentPhonebookError = GE_NONE;
3413     break;
3414
3415   case 0x06:
3416
3417     switch (MessageBuffer[4]) {
3418       /* FIXME: other errors? When I send the phonebook with index of 350 it
3419          still report error 0x7d :-( */
3420       case 0x7d:
3421 #ifdef DEBUG
3422         fprintf(stdout, _("Message: Phonebook not written - name is too long.\n"));
3423 #endif /* DEBUG */
3424         CurrentPhonebookError = GE_PHBOOKNAMETOOLONG;
3425         break;
3426
3427       default:
3428 #ifdef DEBUG
3429         fprintf(stdout, _("   Unknown error!\n"));
3430 #endif /* DEBUG */
3431         CurrentPhonebookError = GE_INTERNALERROR;
3432     }
3433   }
3434 }
3435
3436 /* Routine to write phonebook location in phone. Designed to be called by
3437    application code. Will block until location is written or timeout
3438    occurs. */
3439 GSM_Error N6110_WritePhonebookLocation(GSM_PhonebookEntry *entry)
3440 {
3441   unsigned char req[128] = { N6110_FRAME_HEADER, 0x04, 0x00, 0x00 };
3442   int i=0, current=0;
3443
3444   req[4] = N6110_GetMemoryType(entry->MemoryType);
3445   req[5] = entry->Location;
3446
3447   current=7;
3448
3449   if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {
3450 #ifndef UCLINUX
3451
3452      req[6] = strlen(entry->Name)*2;
3453
3454      EncodeUnicode (req+current,entry->Name ,strlen(entry->Name));
3455      
3456      for (i=0; i<strlen(entry->Name); i++)
3457      {
3458        /* here we encode "special" chars */
3459        if (entry->Name[i]=='~') req[current+i*2]=1; //enables/disables blinking
3460        if (entry->Name[i]=='`') req[current+i*2]=0; //hides rest ot contents
3461      }
3462
3463      current+=strlen(entry->Name)*2;
3464
3465 #else /* UCLINUX */
3466
3467      fprintf(stderr,"FATAL ERROR: EncodeUnicode disabled!\n");
3468      exit(1);
3469
3470 #endif /* UCLINUX */
3471   } else {
3472
3473     req[6] = strlen(entry->Name);
3474
3475     for (i=0; i<strlen(entry->Name); i++)
3476     {
3477       req[current+i] = entry->Name[i];
3478
3479       /* here we encode "special" chars */
3480       if (entry->Name[i]=='~') req[current+i]=1; //enables/disables blinking
3481       if (entry->Name[i]=='`') req[current+i]=0; //hides rest ot contents
3482     }
3483
3484     current+=strlen(entry->Name);
3485   }
3486
3487   req[current++]=strlen(entry->Number);
3488
3489   for (i=0; i<strlen(entry->Number); i++)
3490     req[current+i] = entry->Number[i];
3491
3492   current+=strlen(entry->Number);
3493
3494   /* Jano: This allow to save 14 characters name into SIM memory, when
3495      No Group is selected. */
3496   if (entry->Group == 5)
3497     req[current++]=0xff;
3498   else
3499     req[current++]=entry->Group;
3500
3501   return NULL_SendMessageSequence
3502     (50, &CurrentPhonebookError, current, 0x03, req);
3503 }
3504
3505 #ifndef UCLINUX
3506
3507 void N6110_ReplyNetmonitor(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3508
3509   switch(MessageBuffer[3]) {
3510
3511     case 0x00:
3512 #ifdef DEBUG
3513       fprintf(stdout, _("Message: Netmonitor correctly set.\n"));
3514 #endif /* DEBUG */
3515       CurrentNetmonitorError=GE_NONE;  
3516       break;
3517       
3518     default:
3519 #ifdef DEBUG
3520       fprintf(stdout, _("Message: Netmonitor menu %d received:\n"), MessageBuffer[3]);
3521       fprintf(stdout, "%s\n", MessageBuffer+4);
3522 #endif /* DEBUG */
3523
3524       strcpy(CurrentNetmonitor, MessageBuffer+4);
3525
3526       CurrentNetmonitorError=GE_NONE;  
3527   }
3528 }
3529
3530 GSM_Error N6110_NetMonitor(unsigned char mode, char *Screen)
3531 {
3532   unsigned char req[] = { 0x00, 0x01, 0x7e, 0x00 };
3533   
3534   GSM_Error error;
3535   
3536   error=N6110_EnableExtendedCommands(0x01);
3537   if (error!=GE_NONE) return error;
3538
3539   CurrentNetmonitor=Screen;
3540
3541   req[3]=mode;
3542
3543   return NULL_SendMessageSequence
3544     (20, &CurrentNetmonitorError, 4, 0x40, req);
3545 }
3546
3547 /* Doesn't work in N3210. */
3548 /* In other allow to access phone menu without SIM card (just send any sequence) */
3549 GSM_Error N6110_SendDTMF(char *String)
3550 {
3551   unsigned char req[64] = { N6110_FRAME_HEADER, 0x50,
3552                             0x00 /* Length of DTMF string. */
3553                           };
3554                           
3555   u8 length=strlen(String);
3556
3557   if (length>59) length=59;
3558   
3559   req[4] = length;
3560   
3561   memcpy(req+5,String,length);
3562
3563   return NULL_SendMessageSequence
3564     (20, &CurrentSendDTMFError, 5+length, 0x01, req);
3565 }
3566
3567 #endif /* UCLINUX */
3568
3569 static void N6110_ReplyGetSpeedDial(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3570
3571   switch (MessageBuffer[3]) {
3572
3573   case 0x17:
3574
3575     switch (MessageBuffer[4]) {
3576       case 0x02: CurrentSpeedDialEntry->MemoryType = GMT_ME;
3577       default  : CurrentSpeedDialEntry->MemoryType = GMT_SM;
3578     }
3579       
3580     CurrentSpeedDialEntry->Location = MessageBuffer[5];
3581
3582 #ifdef DEBUG
3583     fprintf(stdout, _("Message: Speed dial entry received:\n"));
3584     fprintf(stdout, _("   Location: %d\n"), CurrentSpeedDialEntry->Location);
3585     fprintf(stdout, _("   MemoryType: %s\n"), N6110_MemoryType_String[CurrentSpeedDialEntry->MemoryType]);
3586     fprintf(stdout, _("   Number: %d\n"), CurrentSpeedDialEntry->Number);
3587 #endif /* DEBUG */
3588
3589     CurrentSpeedDialError=GE_NONE;
3590     break;
3591
3592   case 0x18:
3593
3594 #ifdef DEBUG
3595     fprintf(stdout, _("Message: Speed dial entry error\n"));
3596 #endif /* DEBUG */
3597     CurrentSpeedDialError=GE_INVALIDSPEEDDIALLOCATION;
3598     break;
3599
3600   }
3601 }
3602
3603 GSM_Error N6110_GetSpeedDial(GSM_SpeedDial *entry)
3604 {
3605
3606   unsigned char req[] = { N6110_FRAME_HEADER,
3607                           0x16,
3608                           0x00  /* The number of speed dial. */
3609                         };
3610
3611   CurrentSpeedDialEntry = entry;
3612
3613   req[4] = entry->Number;
3614
3615   return NULL_SendMessageSequence
3616     (20, &CurrentSpeedDialError, 5, 0x03, req);
3617 }
3618
3619 static void N6110_ReplySetSpeedDial(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3620
3621   switch (MessageBuffer[3]) {
3622
3623   case 0x1a:
3624
3625 #ifdef DEBUG
3626     fprintf(stdout, _("Message: Speed dial entry set.\n"));
3627 #endif /* DEBUG */
3628     CurrentSpeedDialError=GE_NONE;
3629     break;
3630
3631   case 0x1b:
3632
3633 #ifdef DEBUG
3634     fprintf(stdout, _("Message: Speed dial entry setting error.\n"));
3635 #endif /* DEBUG */
3636     CurrentSpeedDialError=GE_INVALIDSPEEDDIALLOCATION;
3637     break;
3638
3639   }
3640 }
3641
3642 GSM_Error N6110_SetSpeedDial(GSM_SpeedDial *entry)
3643 {
3644
3645   unsigned char req[] = { N6110_FRAME_HEADER,
3646                           0x19,
3647                           0x00, /* Number */
3648                           0x00, /* Memory Type */
3649                           0x00  /* Location */
3650                         };
3651
3652   req[4] = entry->Number;
3653
3654   switch (entry->MemoryType) {
3655     case GMT_ME: req[5] = 0x02;
3656     default    : req[5] = 0x03;
3657   }
3658
3659   req[6] = entry->Location;
3660
3661   return NULL_SendMessageSequence
3662     (20, &CurrentSpeedDialError, 7, 0x03, req);
3663 }
3664
3665 #ifndef UCLINUX
3666
3667 /* This function finds parts of SMS in frame used in new Nokia phones
3668    in internal protocols (they're coded according to GSM 03.40), copies them
3669    to GSM_ETSISMSMessage and calls GSM_DecodeETSISMS to decode
3670    GSM_ETSISMSMessage to GSM_SMSMessage structure */
3671 GSM_Error GSM_DecodeNokiaSMSFrame(GSM_SMSMessage *SMS, unsigned char *req, int length)
3672 {
3673   SMS_MessageType PDU=SMS_Deliver;
3674   GSM_ETSISMSMessage ETSI;
3675   int offset=0,i;
3676
3677   ETSI.firstbyte=req[12];
3678
3679   /* See GSM 03.40 section 9.2.3.1 */
3680   if ((ETSI.firstbyte & 0x03) == 0x01) PDU=SMS_Submit;
3681   if ((ETSI.firstbyte & 0x03) == 0x02) PDU=SMS_Status_Report;
3682
3683   switch (PDU) {
3684     case SMS_Submit       : offset=5;break;
3685     case SMS_Deliver      : offset=4;break;
3686     case SMS_Status_Report: offset=3;break;
3687     default:                break;
3688   }
3689
3690   for (i=0;i<req[0]+1;i++)
3691     ETSI.SMSCNumber[i]=req[i];
3692
3693   for (i=0;i<((req[12+offset]+1)/2+1)+1;i++)
3694     ETSI.Number[i]=req[i+12+offset];
3695
3696   switch (PDU) {
3697     case SMS_Submit:
3698       ETSI.TPDCS=req[10+offset];
3699       ETSI.TPUDL=req[11+offset];
3700       ETSI.TPVP=0;  //no support for now
3701       ETSI.TPPID=0; //no support for now
3702       for(i=31+offset;i<length;i++)
3703         ETSI.MessageText[i-31-offset]=req[i];
3704       break;
3705     case SMS_Deliver:
3706       ETSI.TPDCS=req[10+offset];
3707       ETSI.TPUDL=req[11+offset];
3708       ETSI.TPPID=0; //no support for now
3709       for(i=31+offset;i<length;i++)
3710         ETSI.MessageText[i-31-offset]=req[i];
3711       for(i=0;i<7;i++)
3712         ETSI.DeliveryDateTime[i]=req[i+24+offset];
3713       break;
3714     case SMS_Status_Report:
3715       for(i=0;i<7;i++)
3716         ETSI.DeliveryDateTime[i]=req[i+24+offset];
3717       ETSI.TPStatus=req[14];
3718       for(i=0;i<7;i++)
3719         ETSI.SMSCDateTime[i]=req[i+34];
3720       break;
3721     default:
3722       break;
3723   }
3724
3725   GSM_DecodeETSISMS(SMS, &ETSI);
3726
3727   SMS->Name[0]=0;
3728
3729   return GE_NONE;
3730 }
3731
3732 void N6110_ReplyGetSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3733
3734   int offset;
3735   
3736   switch (MessageBuffer[3]) {
3737
3738   case 0x08:
3739
3740     switch (MessageBuffer[7]) {
3741
3742       case 0x00:
3743         CurrentSMSMessage->Type = GST_SMS;
3744         CurrentSMSMessage->folder=GST_INBOX;
3745         offset=4;
3746         break;
3747
3748       case 0x01:
3749         CurrentSMSMessage->Type = GST_DR;
3750         CurrentSMSMessage->folder=GST_INBOX;
3751         offset=3;
3752         break;
3753
3754       case 0x02:
3755         CurrentSMSMessage->Type = GST_SMS;
3756         CurrentSMSMessage->folder=GST_OUTBOX;
3757         offset=5;
3758         break;
3759
3760       default:
3761         CurrentSMSMessage->Type = GST_UN;
3762         offset=4;
3763         break;
3764
3765     }
3766
3767     /* Field Short Message Status - MessageBuffer[4] seems not to be
3768        compliant with GSM 07.05 spec.
3769        Meaning     Nokia protocol       GMS spec
3770        ----------------------------------------------------
3771        MO Sent     0x05                 0x07 or 0x01
3772        MO Not sent 0x07                 0x06 or 0x00
3773        MT Read     0x01                 0x05 or 0x01
3774        MT Not read 0x03                 0x04 or 0x00
3775        ----------------------------------------------------
3776        See GSM 07.05 section 2.5.2.6 and correct me if I'm wrong.
3777        
3778                                          Pawel Kot */
3779
3780     if (MessageBuffer[4] & 0x02) CurrentSMSMessage->Status = GSS_NOTSENTREAD;
3781                             else CurrentSMSMessage->Status = GSS_SENTREAD;
3782
3783 #ifdef DEBUG
3784     fprintf(stdout, _("Number: %d\n"), MessageBuffer[6]);
3785
3786     if (CurrentSMSMessage->folder!=1) { //GST_OUTBOX
3787       fprintf(stdout, _("Message: Received SMS (mobile terminated)\n"));
3788     } else {
3789       fprintf(stdout, _("Message: Outbox message (mobile originated)\n"));
3790     }
3791
3792     if (CurrentSMSMessage->Type == GST_DR) fprintf(stdout, _("   Delivery Report\n"));
3793     if (CurrentSMSMessage->Type == GST_UN) fprintf(stdout, _("   Unknown type\n"));
3794
3795     if (CurrentSMSMessage->folder==1) { //GST_OUTBOX
3796       if (CurrentSMSMessage->Status) fprintf(stdout, _("   Sent\n"));
3797                                 else fprintf(stdout, _("   Not sent\n"));
3798     } else {
3799       if (CurrentSMSMessage->Status) fprintf(stdout, _("   Read\n"));
3800                                 else fprintf(stdout, _("   Not read\n"));
3801     }
3802 #endif
3803
3804     CurrentSMSPointer=GSM_DecodeNokiaSMSFrame(CurrentSMSMessage, MessageBuffer+8, MessageLength-8);
3805
3806     CurrentSMSMessage->MemoryType = MessageBuffer[5];
3807     CurrentSMSMessage->MessageNumber = MessageBuffer[6];
3808  
3809     /* Signal no error to calling code. */
3810     CurrentSMSMessageError = GE_NONE;
3811
3812 #ifdef DEBUG
3813     fprintf(stdout, "\n");
3814 #endif
3815
3816     break;
3817
3818   case 0x09:
3819
3820     /* We have requested invalid or empty location. */
3821
3822 #ifdef DEBUG
3823     fprintf(stdout, _("Message: SMS reading failed\n"));
3824
3825     switch (MessageBuffer[4]) {
3826       case 0x02:
3827         fprintf(stdout, _("   Invalid location!\n"));break;
3828       case 0x07:
3829         fprintf(stdout, _("   Empty SMS location.\n"));break;
3830       case 0x0c:
3831         fprintf(stdout, _("   No access to memory (no PIN on card ?)\n"));break;
3832       default:      
3833         fprintf(stdout, _("   Error code %i - please report it \n"),MessageBuffer[4]);break;
3834     }
3835 #endif /* DEBUG */
3836
3837     switch (MessageBuffer[4]) {
3838       case 0x02:CurrentSMSMessageError = GE_INVALIDSMSLOCATION;break;
3839       case 0x07:CurrentSMSMessageError = GE_EMPTYSMSLOCATION;break;
3840       case 0x0c:CurrentSMSMessageError = GE_NOACCESS;break;
3841       default  :CurrentSMSMessageError = GE_UNKNOWN;break;
3842     }
3843
3844     break;
3845
3846   }
3847 }
3848
3849 GSM_Error N6110_GetSMSMessage(GSM_SMSMessage *message)
3850 {
3851
3852   unsigned char req[] = { N6110_FRAME_HEADER,
3853                           0x07,
3854                           0x02, /* Unknown */
3855                           0x00, /* Location */
3856                           0x01, 0x64};
3857
3858   int timeout = 60;
3859
3860   /* State machine code writes data to these variables when it comes in. */
3861
3862   CurrentSMSMessage = message;
3863   CurrentSMSMessageError = GE_BUSY;
3864
3865   req[5] = message->Location;
3866
3867   /* Send request */
3868   Protocol->SendMessage(8, 0x02, req);
3869
3870   /* Wait for timeout or other error. */
3871   while (timeout != 0 && (CurrentSMSMessageError == GE_BUSY || CurrentSMSMessageError == GE_SMSWAITING)) {
3872
3873     if (--timeout == 0)
3874       return (GE_TIMEOUT);
3875
3876     usleep (100000);
3877   }
3878
3879   return (CurrentSMSMessageError);
3880 }
3881
3882 void N6110_ReplyDeleteSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3883
3884 #ifdef DEBUG
3885   fprintf(stdout, _("Message: SMS deleted successfully.\n"));
3886 #endif /* DEBUG */
3887
3888   CurrentSMSMessageError = GE_NONE;     
3889 }
3890
3891 GSM_Error N6110_DeleteSMSMessage(GSM_SMSMessage *message)
3892 {
3893   unsigned char req[] = {N6110_FRAME_HEADER, 0x0a, 0x02, 0x00};
3894
3895   req[5] = message->Location;
3896
3897   return NULL_SendMessageSequence
3898     (50, &CurrentSMSMessageError, 6, 0x14, req);
3899 }
3900
3901 /* FIXME: do we need more than SMS_Submit and SMS_Deliver ? */
3902 GSM_Error GSM_EncodeNokiaSMSFrame(GSM_SMSMessage *SMS, unsigned char *req, int *length, SMS_MessageType PDU)
3903 {
3904   GSM_ETSISMSMessage ETSI;
3905   int i,offset=0;
3906
3907   GSM_EncodeETSISMS(SMS, &ETSI, PDU, length);
3908
3909   /* Cleaning */
3910   for (i=0;i<36;i++) req[i]=0;
3911
3912   req[12]=ETSI.firstbyte;
3913
3914   for (i=0;i<ETSI.SMSCNumber[0]+1;i++)
3915     req[i]=ETSI.SMSCNumber[i];
3916
3917   switch (PDU) {
3918     case SMS_Submit:
3919       offset=5;
3920       for (i=0;i<((ETSI.Number[0]+1)/2+1)+1;i++)
3921         req[i+12+offset]=ETSI.Number[i];
3922       req[10+offset]=ETSI.TPDCS;
3923       req[11+offset]=ETSI.TPUDL;
3924       req[24+offset]=ETSI.TPVP;
3925 #ifdef DEBUG
3926 //      fprintf(stdout,_("   First byte: %02x\n"),ETSI.firstbyte);
3927 //      fprintf(stdout,_("   TP-VP: %02x\n"),ETSI.TPVP);
3928 //      fprintf(stdout,_("   TP-DCS: %02x\n"),ETSI.TPDCS);
3929 #endif
3930 //    req[]=ETSI.TPPID;
3931       for(i=0;i<*length;i++)
3932         req[i+31+offset]=ETSI.MessageText[i];
3933       break;
3934
3935     case SMS_Deliver:
3936       offset=4;
3937       for (i=0;i<((ETSI.Number[0]+1)/2+1)+1;i++)
3938         req[i+12+offset]=ETSI.Number[i];
3939       req[10+offset]=ETSI.TPDCS;
3940       req[11+offset]=ETSI.TPUDL;
3941 //    req[]=ETSI.TPPID;
3942       for(i=0;i<*length;i++)
3943         req[i+31+offset]=ETSI.MessageText[i];
3944       for (i=0;i<7;i++)
3945         req[24+offset+i]=ETSI.DeliveryDateTime[i];
3946       break;
3947     default:
3948       break;
3949   }
3950   
3951   *length=*length+offset;
3952   
3953   return GE_NONE;
3954 }
3955
3956 void N6110_ReplySendSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3957     
3958   switch (MessageBuffer[3]) {
3959
3960   /* SMS message correctly sent to the network */
3961   case 0x02:
3962 #ifdef DEBUG
3963     fprintf(stdout, _("Message: SMS Message correctly sent.\n"));
3964 #endif /* DEBUG */
3965     CurrentSMSMessageError = GE_SMSSENDOK;
3966     break;
3967
3968   /* SMS message send to the network failed */
3969   case 0x03:
3970
3971 #ifdef DEBUG
3972     fprintf(stdout, _("Message: Sending SMS Message failed, error: %i"),MessageBuffer[6]);
3973       
3974     switch (MessageBuffer[6]) {
3975       case 1: fprintf(stdout,_(" (info \"Number not in use\")"));break;
3976       case 21: fprintf(stdout,_(" (info \"Message not sent this time\")"));break;
3977       case 28: fprintf(stdout,_(" (info \"Number not in use\")"));break;
3978       case 38: fprintf(stdout,_(" (info \"Message not sent this time\")"));break;       case 50: fprintf(stdout,_(" (info \"Check operator services\")"));break;        
3979       case 96: fprintf(stdout,_(" (info \"Message sending failed\")"));break;   
3980       case 111: fprintf(stdout,_(" (info \"Message sending failed\")"));break;  
3981       case 166: fprintf(stdout,_(" (info \"Message sending failed\")"));break;  
3982       case 178: fprintf(stdout,_(" (info \"Message sending failed\")"));break;  
3983       case 252: fprintf(stdout,_(" (info \"Message sending failed\")"));break;         case 253: fprintf(stdout,_(" (info \"Message sending failed\")"));break; 
3984     }
3985
3986     fprintf(stdout,_("\n   For more details with errors see netmonitor manual (test 65) on www.marcin-wiacek.topnet.pl"));
3987     fprintf(stdout,_("\n   If know their meaning, GSM specs decribing them, contact with me on marcin-wiacek@topnet.pl. THX\n"));
3988 #endif /* DEBUG */
3989
3990     CurrentSMSMessageError = GE_SMSSENDFAILED;
3991     break;
3992
3993   }
3994 }
3995
3996 GSM_Error N6110_SendSMSMessage(GSM_SMSMessage *SMS)
3997 {
3998   GSM_Error error;
3999
4000   unsigned char req[256] = {
4001     N6110_FRAME_HEADER,
4002     0x01, 0x02, 0x00, /* SMS send request*/
4003   };
4004
4005   int length;
4006
4007   error=GSM_EncodeNokiaSMSFrame(SMS, req+6, &length, SMS_Submit);    
4008   if (error != GE_NONE) return error;
4009
4010   return NULL_SendMessageSequence
4011     (200, &CurrentSMSMessageError, 42+length, 0x02, req);
4012 }
4013
4014 void N6110_ReplySaveSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4015
4016   switch (MessageBuffer[3]) {
4017
4018   case 0x05:
4019       
4020 #ifdef DEBUG
4021     fprintf(stdout, _("SMS Message stored at %d\n"), MessageBuffer[5]);
4022 #endif
4023       
4024     CurrentSMSMessage->MessageNumber=MessageBuffer[5];
4025       
4026     CurrentSMSMessageError = GE_NONE;
4027     break;
4028
4029   case 0x06:
4030 #ifdef DEBUG
4031     fprintf(stdout, _("SMS saving failed\n"));
4032     switch (MessageBuffer[4]) {
4033       case 0x02:fprintf(stdout, _("   All locations busy.\n"));break;
4034       case 0x03:fprintf(stdout, _("   Invalid location!\n"));break;
4035       default  :fprintf(stdout, _("   Unknown error.\n"));break;
4036     }
4037 #endif      
4038       
4039     switch (MessageBuffer[4]) {
4040       case 0x02:CurrentSMSMessageError = GE_MEMORYFULL;break;
4041       case 0x03:CurrentSMSMessageError = GE_INVALIDSMSLOCATION;break;
4042       default  :CurrentSMSMessageError = GE_UNKNOWN;break;
4043     }
4044   }
4045 }
4046
4047 /* GST_DR and GST_UN not supported ! */
4048 GSM_Error N6110_SaveSMSMessage(GSM_SMSMessage *SMS)
4049 {
4050   unsigned char req[256] = {
4051     N6110_FRAME_HEADER, 0x04, /* SMS save request*/
4052     0x00, /* SMS Status. Different for Inbox and Outbox */
4053     0x02, /* ?? */
4054     0x00, /* SMS Location */
4055     0x02, /* SMS Type */
4056   };
4057
4058   int length;
4059   SMS_MessageType PDU;
4060   GSM_Error error;
4061
4062   if (SMS->Location) req[6] = SMS->Location;
4063     
4064   if (SMS->folder==0) { /*Inbox*/
4065     req[4]=1;      /* SMS Status */
4066     req[7] = 0x00; /* SMS Type */
4067     PDU=SMS_Deliver;
4068   } else {
4069     req[4]=5;      /* SMS Status */
4070     req[7] = 0x02; /* SMS Type */
4071     PDU=SMS_Submit;
4072   }
4073   
4074   if (SMS->Status == GSS_NOTSENTREAD) req[4] |= 0x02;  
4075
4076   error=GSM_EncodeNokiaSMSFrame(SMS, req+8, &length, PDU);  
4077   if (error != GE_NONE) return error;
4078
4079   CurrentSMSMessage = SMS;
4080
4081   return NULL_SendMessageSequence
4082     (70, &CurrentSMSMessageError, 39+length, 0x14, req);
4083 }
4084
4085 void N6110_ReplySetCellBroadcast(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4086
4087 #ifdef DEBUG
4088   fprintf(stdout, _("Message: Cell Broadcast enabled/disabled successfully.\n")); fflush (stdout);
4089 #endif
4090
4091   CurrentCBError = GE_NONE;
4092 }
4093
4094 /* Enable and disable Cell Broadcasting */
4095 GSM_Error N6110_EnableCellBroadcast(void)
4096 {
4097   unsigned char req[] = {N6110_FRAME_HEADER, 0x20,
4098                          0x01, 0x01, 0x00, 0x00, 0x01, 0x01};
4099
4100 #ifdef DEBUG
4101   fprintf (stdout,"Enabling CB\n");
4102 #endif
4103
4104   CurrentCBMessage = (GSM_CBMessage *)malloc(sizeof (GSM_CBMessage));
4105   CurrentCBMessage->Channel = 0;
4106   CurrentCBMessage->New = false;
4107   strcpy (CurrentCBMessage->Message,"");
4108
4109   return NULL_SendMessageSequence
4110     (10, &CurrentCBError, 10, 0x02, req);
4111 }
4112
4113
4114 GSM_Error N6110_DisableCellBroadcast(void)
4115 {
4116   /* Should work, but not tested fully */
4117
4118   unsigned char req[] = {N6110_FRAME_HEADER, 0x20,
4119                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /*VERIFY*/
4120
4121   return NULL_SendMessageSequence
4122     (10, &CurrentCBError, 10, 0x02, req);
4123 }
4124
4125 void N6110_ReplyReadCellBroadcast(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4126
4127   int i, tmp;
4128   unsigned char output[160];
4129   
4130   CurrentCBMessage->Channel = MessageBuffer[7];
4131   CurrentCBMessage->New = true;
4132   tmp=GSM_UnpackEightBitsToSeven(0, MessageBuffer[9], MessageBuffer[9], MessageBuffer+10, output);
4133
4134 #ifdef DEBUG
4135   fprintf(stdout, _("Message: CB received.\n")); fflush (stdout);
4136
4137   fprintf(stdout, _("Message: channel number %i\n"),MessageBuffer[7]);
4138
4139   fflush (stdout);
4140
4141   for (i=0; i<tmp;i++) {
4142     fprintf(stdout, "%c", DecodeWithDefaultAlphabet(output[i]));
4143   }
4144
4145   fprintf(stdout, "\n");
4146 #endif
4147    
4148   for (i=0; i<tmp; i++) {
4149     CurrentCBMessage->Message[i] = DecodeWithDefaultAlphabet(output[i]);
4150   }
4151   CurrentCBMessage->Message[i]=0;
4152 }
4153
4154 GSM_Error N6110_ReadCellBroadcast(GSM_CBMessage *Message)
4155 {
4156 #ifdef DEBUG
4157    fprintf(stdout,"Reading CB\n");
4158 #endif
4159
4160   if (CurrentCBMessage != NULL) 
4161   {
4162     if (CurrentCBMessage->New == true)
4163     {
4164 #ifdef DEBUG
4165   fprintf(stdout,"New CB received\n");
4166 #endif
4167       Message->Channel = CurrentCBMessage->Channel;
4168       strcpy(Message->Message,CurrentCBMessage->Message);
4169       CurrentCBMessage->New = false;
4170       return (GE_NONE);
4171     }
4172   }
4173   return (GE_NONEWCBRECEIVED);
4174 }
4175
4176 int N6110_MakeCallerGroupFrame(unsigned char *req,GSM_Bitmap Bitmap)
4177 {
4178   int count=0;
4179
4180   req[count++]=Bitmap.number;
4181   req[count++]=strlen(Bitmap.text);
4182   memcpy(req+count,Bitmap.text,req[count-1]);
4183   count+=req[count-1];
4184   req[count++]=Bitmap.ringtone;
4185
4186   /* Setting for graphic:
4187      0x00 - Off
4188      0x01 - On
4189      0x02 - View Graphics
4190      0x03 - Send Graphics
4191      0x04 - Send via IR
4192      You can even set it higher but Nokia phones (my
4193      6110 at least) will not show you the name of this
4194      item in menu ;-)) Nokia is really joking here. */
4195   if (Bitmap.enabled) req[count++]=0x01;
4196                  else req[count++]=0x00;
4197
4198   req[count++]=(Bitmap.size+4)>>8;
4199   req[count++]=(Bitmap.size+4)%0xff;
4200   req[count++]=0x00;  /* Future extensions! */
4201   req[count++]=Bitmap.width;
4202   req[count++]=Bitmap.height;
4203   req[count++]=0x01;  /* Just BW */
4204   memcpy(req+count,Bitmap.bitmap,Bitmap.size);
4205
4206   return count+Bitmap.size;
4207 }
4208
4209 int N6110_MakeOperatorLogoFrame(unsigned char *req,GSM_Bitmap Bitmap)
4210 {
4211   int count=0;
4212
4213   EncodeNetworkCode(req+count, Bitmap.netcode);
4214   count=count+3;
4215
4216   req[count++]=(Bitmap.size+4)>>8;
4217   req[count++]=(Bitmap.size+4)%0xff;
4218   req[count++]=0x00;  /* Infofield */
4219   req[count++]=Bitmap.width;
4220   req[count++]=Bitmap.height;
4221   req[count++]=0x01;  /* Just BW */    
4222   memcpy(req+count,Bitmap.bitmap,Bitmap.size);
4223
4224   return count+Bitmap.size;
4225 }
4226
4227 int N6110_MakeStartupLogoFrame(unsigned char *req,GSM_Bitmap Bitmap)
4228 {
4229   int count=0;
4230
4231   req[count++]=0x01;
4232   req[count++]=Bitmap.height;
4233   req[count++]=Bitmap.width;
4234   memcpy(req+count,Bitmap.bitmap,Bitmap.size);
4235
4236   return count+Bitmap.size;
4237 }
4238
4239 /* Set a bitmap or welcome-note */
4240 GSM_Error N6110_SetBitmap(GSM_Bitmap *Bitmap) {
4241
4242   unsigned char req[600] = { N6110_FRAME_HEADER };
4243   u16 count=3;
4244   u8 textlen;
4245   
4246   int timeout=50;
4247
4248   /* Direct uploading variables */
4249   GSM_MultiSMSMessage SMS;
4250   unsigned char buffer[1000] = {0x0c,0x01};
4251   GSM_NetworkInfo NetworkInfo;
4252
4253   GSM_Error error;
4254  
4255   /* Uploading with preview */
4256   if (Bitmap->number==255 &&
4257      (Bitmap->type==GSM_OperatorLogo || Bitmap->type==GSM_CallerLogo)) {
4258     GSM_SaveBitmapToSMS(&SMS,Bitmap,false,false);
4259     memcpy(buffer+2,SMS.SMS[0].UDH,SMS.SMS[0].UDH[0]+1);
4260
4261     memcpy(buffer+2+SMS.SMS[0].UDH[0]+1,SMS.SMS[0].MessageText,SMS.SMS[0].Length);
4262
4263     buffer[2+SMS.SMS[0].UDH[0]+1+SMS.SMS[0].Length]=0x00;
4264
4265     Protocol->SendMessage(2+SMS.SMS[0].UDH[0]+1+SMS.SMS[0].Length+1, 0x12, buffer);
4266
4267     GSM->GetNetworkInfo(&NetworkInfo); //need to make something
4268     return GE_NONE; //no answer from phone
4269   }
4270  
4271   CurrentSetBitmapError = GE_BUSY;  
4272   
4273   switch (Bitmap->type) {
4274   case GSM_WelcomeNoteText:
4275   case GSM_DealerNoteText:
4276     req[count++]=0x18;
4277     req[count++]=0x01; /* Only one block */
4278
4279     if (Bitmap->type==GSM_WelcomeNoteText)
4280       req[count++]=0x02; /* Welcome text */
4281     else
4282       req[count++]=0x03; /* Dealer Welcome Note */
4283
4284     textlen=strlen(Bitmap->text);
4285     req[count++]=textlen;
4286     memcpy(req+count,Bitmap->text,textlen);
4287       
4288     count+=textlen;
4289
4290     Protocol->SendMessage(count, 0x05, req);
4291     
4292     break;
4293
4294   case GSM_StartupLogo:
4295     if (Bitmap->number==0) {
4296
4297       /* For 33xx we first set animated logo to default */
4298       if (GetModelFeature (FN_STARTUP)==F_STANIM) {
4299         error=N6110_SetProfileFeature(0, 0x29, Bitmap->number);
4300         if (error!=GE_NONE) return error;
4301       }
4302
4303       req[count++]=0x18;
4304       req[count++]=0x01; /* Only one block */
4305       count=count+N6110_MakeStartupLogoFrame(req+5,*Bitmap); 
4306       Protocol->SendMessage(count, 0x05, req);
4307     } else {
4308       return N6110_SetProfileFeature(0, 0x29, Bitmap->number);
4309     }
4310     break;
4311
4312   case GSM_OperatorLogo:
4313     req[count++]=0x30;  /* Store Op Logo */
4314     req[count++]=0x01;  /* Location */
4315     count=count+N6110_MakeOperatorLogoFrame(req+5,*Bitmap); 
4316     Protocol->SendMessage(count, 0x05, req);
4317     break;
4318
4319   case GSM_CallerLogo:
4320     req[count++]=0x13;
4321     count=count+N6110_MakeCallerGroupFrame(req+4,*Bitmap);
4322     Protocol->SendMessage(count, 0x03, req);
4323     break;
4324
4325   case GSM_PictureImage:
4326     req[count++]=0x03;
4327     req[count++]=Bitmap->number;
4328     if (strcmp(Bitmap->Sender,"")) {
4329        req[count]=GSM_PackSemiOctetNumber(Bitmap->Sender, req+count+1,true);
4330
4331        /* Convert number of semioctets to number of chars and add count */
4332        textlen=req[count];
4333        if (textlen % 2) textlen++;
4334        count+=textlen / 2 + 1;
4335
4336        count++;
4337     } else {
4338       req[count++]=0x00;
4339       req[count++]=0x00;
4340     }
4341     req[count++]=0x00;
4342     req[count++]=strlen(Bitmap->text);
4343     memcpy(req+count,Bitmap->text,strlen(Bitmap->text));
4344     count+=strlen(Bitmap->text);
4345     req[count++]=0x00;
4346     req[count++]=Bitmap->width;
4347     req[count++]=Bitmap->height;
4348     req[count++]=0x01;
4349     memcpy(req+count,Bitmap->bitmap,Bitmap->size);
4350     Protocol->SendMessage(count+Bitmap->size, 0x47, req);
4351     break;
4352
4353   case GSM_7110OperatorLogo:
4354   case GSM_7110StartupLogo:
4355   case GSM_6210StartupLogo:
4356     return GE_NOTSUPPORTED;
4357
4358   case GSM_None:
4359     return GE_NONE;
4360   }
4361
4362   /* Wait for timeout or other error. */
4363   while (timeout != 0 && CurrentSetBitmapError == GE_BUSY ) {
4364           
4365     if (--timeout == 0)
4366       return (GE_TIMEOUT);
4367                     
4368     usleep (100000);
4369   }
4370
4371   return CurrentSetBitmapError;
4372 }
4373
4374 /* Get a bitmap from the phone */
4375 GSM_Error N6110_GetBitmap(GSM_Bitmap *Bitmap) {
4376
4377   unsigned char req[10] = { N6110_FRAME_HEADER };
4378   u8 count=3;
4379   
4380   int timeout=100;
4381   
4382   CurrentGetBitmap=Bitmap; 
4383   CurrentGetBitmapError = GE_BUSY;  
4384   
4385   switch (CurrentGetBitmap->type) {
4386   case GSM_StartupLogo:
4387   case GSM_WelcomeNoteText:
4388   case GSM_DealerNoteText:
4389     req[count++]=0x16;
4390     Protocol->SendMessage(count, 0x05, req);
4391     break;
4392   case GSM_OperatorLogo:
4393     req[count++]=0x33;
4394     req[count++]=0x01; /* Location 1 */
4395     Protocol->SendMessage(count, 0x05, req);
4396     break;
4397   case GSM_CallerLogo:
4398     req[count++]=0x10;
4399     req[count++]=Bitmap->number;
4400     Protocol->SendMessage(count, 0x03, req);
4401     break;
4402   case GSM_PictureImage:
4403     req[count++]=0x01;
4404     req[count++]=Bitmap->number;
4405     Protocol->SendMessage(count, 0x47, req);
4406     break;
4407   case GSM_7110OperatorLogo:
4408   case GSM_7110StartupLogo:
4409   case GSM_6210StartupLogo:
4410   default:
4411     return GE_NOTSUPPORTED;
4412   }
4413
4414   /* Wait for timeout or other error. */
4415   while (timeout != 0 && CurrentGetBitmapError == GE_BUSY ) {
4416           
4417     if (--timeout == 0)
4418       return (GE_TIMEOUT);
4419                     
4420     usleep (100000);
4421   }
4422
4423   CurrentGetBitmap=NULL;
4424
4425   return CurrentGetBitmapError;
4426 }
4427
4428 void N6110_ReplySetRingtone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4429
4430   switch (MessageBuffer[3]) {
4431
4432   /* Set ringtone OK */
4433   case 0x37:       
4434 #ifdef DEBUG
4435     fprintf(stdout, _("Message: Ringtone set OK!\n"));
4436 #endif  
4437     CurrentRingtoneError=GE_NONE; 
4438     break;      
4439
4440   /* Set ringtone error */
4441   case 0x38:       
4442 #ifdef DEBUG
4443     fprintf(stdout, _("Message: Ringtone setting error !\n"));
4444 #endif  
4445     CurrentRingtoneError=GE_NOTSUPPORTED; 
4446     break;      
4447   }
4448 }
4449
4450 GSM_Error N6110_SetRingTone(GSM_Ringtone *ringtone, int *maxlength)
4451 {
4452   
4453   char req[FB61_MAX_RINGTONE_FRAME_LENGTH+10] =
4454       {N6110_FRAME_HEADER,
4455        0x36,
4456        0x00,  /* Location */
4457        0x00,0x78};
4458
4459   int size=FB61_MAX_RINGTONE_FRAME_LENGTH;
4460  
4461   /* Variables for preview uploading */
4462   unsigned char buffer[FB61_MAX_RINGTONE_FRAME_LENGTH+50];
4463   unsigned char buffer2[20];
4464   GSM_NetworkInfo NetworkInfo;
4465
4466   /* Setting ringtone with preview */
4467   if (ringtone->location==255) {
4468     buffer[0]=0x0c;
4469     buffer[1]=0x01;
4470     EncodeUDHHeader(buffer2, GSM_RingtoneUDH);
4471     memcpy(buffer+2,buffer2,buffer2[0]+1); //copying UDH
4472     *maxlength=GSM_PackRingtone(ringtone, buffer+2+buffer2[0]+1, &size); //packing ringtone
4473     Protocol->SendMessage(2+buffer2[0]+1+size, 0x12, buffer); //sending frame
4474     GSM->GetNetworkInfo(&NetworkInfo); //need to make something
4475     sleep(1);
4476     return GE_NONE; //no answer from phone
4477   }
4478   
4479   *maxlength=GSM_PackRingtone(ringtone, req+7, &size);
4480
4481   req[4]=ringtone->location-1;
4482
4483   return NULL_SendMessageSequence
4484     (50, &CurrentRingtoneError, (size+7), 0x05, req);
4485 }
4486
4487 void N6110_ReplyGetBinRingtone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4488
4489   int i;
4490   
4491   switch (MessageBuffer[4]) {
4492     case 0x00: /* location supported. We have ringtone */
4493
4494       /* Binary format used in N6150 */
4495       if (MessageBuffer[5]==0x0c && MessageBuffer[6]==0x01 && MessageBuffer[7]==0x2c) {
4496 #ifdef DEBUG
4497         fprintf(stdout,_("Message: ringtone \""));
4498 #endif      
4499
4500         /* Copying name */
4501         i=8;
4502         while (true) {
4503 #ifdef DEBUG
4504           if (MessageBuffer[i]!=0)
4505             fprintf(stdout,_("%c"),MessageBuffer[i]);
4506 #endif
4507           CurrentGetBinRingtone->name[i-8]=MessageBuffer[i];
4508           if (MessageBuffer[i]==0) break;
4509           i++;
4510         }
4511
4512 #ifdef DEBUG    
4513         fprintf(stdout,_("\" received from location %i\n"),MessageBuffer[3]+1);
4514 #endif
4515       
4516         /* Looking for end */
4517         i=0;
4518         while (true) {
4519           if (MessageBuffer[i]==0x07 && MessageBuffer[i+1]==0x0b) {
4520             i=i+2;break;
4521           }
4522           if (MessageBuffer[i]==0x0e && MessageBuffer[i+1]==0x0b) {
4523             i=i+2;break;
4524           }
4525           i++;
4526           if (i==MessageLength) break;
4527         }
4528           
4529         /* Copying frame */
4530         memcpy(CurrentGetBinRingtone->frame,MessageBuffer+3,i-3);
4531         CurrentGetBinRingtone->length=i-3;
4532       
4533         CurrentBinRingtoneError=GE_NONE;
4534         break;
4535       }
4536           
4537       /* Binary format used in N3210 */
4538       if (MessageBuffer[5]==0x10 && MessageBuffer[6]==0x01 && MessageBuffer[7]==0x2c) {      
4539
4540 #ifdef DEBUG
4541         fprintf(stdout,_("Message: ringtone \""));
4542 #endif      
4543
4544         /* Copying name */
4545         i=8;
4546         while (true) {
4547 #ifdef DEBUG
4548           if (MessageBuffer[i]!=0)
4549             fprintf(stdout,_("%c"),MessageBuffer[i]);
4550 #endif
4551           CurrentGetBinRingtone->name[i-8]=MessageBuffer[i];
4552           if (MessageBuffer[i]==0) break;
4553           i++;
4554         }
4555
4556 #ifdef DEBUG    
4557         fprintf(stdout,_("\" received from location %i\n"),MessageBuffer[3]+1);
4558 #endif
4559
4560         /* Here changes to get full compatibility with binary format used in N6150 */
4561         MessageBuffer[3]=0;
4562         MessageBuffer[4]=0;
4563         MessageBuffer[5]=0x0c;
4564         MessageBuffer[6]=0x01;
4565         MessageBuffer[7]=0x2c;
4566
4567         /* Looking for end */
4568         i=0;
4569         while (true) {
4570           if (MessageBuffer[i]==0x07 && MessageBuffer[i+1]==0x0b) {
4571             i=i+2;break;
4572           }
4573           if (MessageBuffer[i]==0x0e && MessageBuffer[i+1]==0x0b) {
4574             i=i+2;break;
4575           }
4576           i++;
4577           if (i==MessageLength) break;
4578         }
4579           
4580         /* Copying frame */
4581         memcpy(CurrentGetBinRingtone->frame,MessageBuffer+3,i-3);
4582
4583         CurrentGetBinRingtone->length=i-3;
4584             
4585         CurrentBinRingtoneError=GE_NONE;          
4586         break;
4587       }
4588
4589       /* Copying frame */
4590       memcpy(CurrentGetBinRingtone->frame,MessageBuffer,MessageLength);
4591
4592       CurrentGetBinRingtone->length=MessageLength;
4593
4594 #ifdef DEBUG    
4595       fprintf(stdout,_("Message: unknown binary format for ringtone received from location %i\n"),MessageBuffer[3]+1);
4596 #endif
4597       CurrentBinRingtoneError=GE_UNKNOWNMODEL;
4598       break;
4599
4600     default:
4601
4602 #ifdef DEBUG
4603       fprintf(stdout,_("Message: Phone doesn't support downloaded ringtones at location %i\n"),MessageBuffer[3]+1);
4604 #endif
4605
4606       CurrentBinRingtoneError=GE_INVALIDRINGLOCATION;  
4607   }
4608 }
4609
4610 GSM_Error N6110_GetBinRingTone(GSM_BinRingtone *ringtone)
4611 {
4612   unsigned char req[] = { 0x00,0x01,0x9e,
4613                           0x00 }; //location
4614
4615   GSM_Error error;
4616   
4617   CurrentGetBinRingtone=ringtone;
4618   
4619   error=N6110_EnableExtendedCommands(0x01);
4620   if (error!=GE_NONE) return error;
4621
4622   req[3]=ringtone->location-1;
4623   
4624   return NULL_SendMessageSequence
4625     (50, &CurrentBinRingtoneError, 4, 0x40, req);
4626 }
4627
4628 void N6110_ReplySetBinRingtone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4629
4630   switch (MessageBuffer[4]) {
4631     case 0x00: /* location supported. We set ringtone */
4632 #ifdef DEBUG
4633       fprintf(stdout,_("Message: downloaded ringtone set at location %i\n"),MessageBuffer[3]+1);
4634 #endif
4635       CurrentBinRingtoneError=GE_NONE;
4636       break;
4637
4638     default:
4639 #ifdef DEBUG
4640       fprintf(stdout,_("Message: Phone doesn't support downloaded ringtones at location %i\n"),MessageBuffer[3]+1);
4641 #endif
4642       CurrentBinRingtoneError=GE_NOTSUPPORTED;    
4643       break;
4644   }
4645 }
4646
4647 GSM_Error N6110_SetBinRingTone(GSM_BinRingtone *ringtone)
4648 {
4649   unsigned char req[1000] = { 0x00,0x01,0xa0};
4650
4651   GSM_Error error;
4652
4653   GSM_BinRingtone ring;
4654
4655   /* Must be sure, that can upload ringtone to this phone */
4656   ring.location=ringtone->location;
4657   error=N6110_GetBinRingTone(&ring);
4658   if (error!=GE_NONE) return error;
4659     
4660   error=N6110_EnableExtendedCommands(0x01);
4661   if (error!=GE_NONE) return error;
4662   
4663   memcpy(req+3,ringtone->frame,ringtone->length);
4664
4665   req[3]=ringtone->location-1;
4666   
4667   return NULL_SendMessageSequence
4668     (50, &CurrentBinRingtoneError, ringtone->length+3, 0x40, req);
4669 }
4670
4671 #endif /* UCLINUX */
4672
4673 GSM_Error N6110_Reset(unsigned char type)
4674 {  
4675   return N6110_EnableExtendedCommands(type);
4676 }
4677
4678 void N6110_Dispatch0x01Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4679
4680   int count;
4681 #ifdef DEBUG
4682         int tmp;
4683 #endif
4684           
4685   switch (MessageBuffer[3]) {
4686
4687   /* Unknown message - it has been seen after the 0x07 message (call
4688      answered). Probably it has similar meaning. If you can solve
4689      this - just mail me. Pavel Janík ml.
4690
4691      The message looks like this:
4692
4693      Msg Destination: PC
4694      Msg Source: Phone
4695      Msg Type: 01
4696      Msg Unknown: 00
4697      Msg Len: 0e
4698
4699      Phone: [01 ][08 ][00 ] is the header of the frame
4700
4701      [03 ] is the call message subtype
4702
4703      [05 ] is the call sequence number
4704
4705      [05 ] unknown 
4706
4707      [00 ][01 ][03 ][02 ][91][00] are unknown but has been
4708      seen in the Incoming call message (just after the
4709      caller's name from the phonebook). But never change
4710      between phone calls :-(
4711   */
4712
4713   /* This may mean sequence number of 'just made' call - CK */
4714   case 0x02:
4715
4716 #ifdef DEBUG
4717     fprintf(stdout, _("Message: Call message, type 0x02:"));
4718     fprintf(stdout, _("   Exact meaning not known yet, sorry :-(\n"));
4719 #endif /* DEBUG */
4720
4721     break;
4722
4723   /* Possibly call OK */
4724   /* JD: I think that this means "call in progress" (incomming or outgoing) */
4725   case 0x03:
4726     
4727 #ifdef DEBUG
4728     fprintf(stdout, _("Message: Call message, type 0x03:"));
4729     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4730     fprintf(stdout, _("   Exact meaning not known yet, sorry :-(\n"));
4731 #endif /* DEBUG */
4732     
4733     CurrentCallSequenceNumber=MessageBuffer[4];
4734 #ifndef UCLINUX
4735     CurrentIncomingCall[0]='D';
4736 #endif /* UCLINUX */
4737     if (CurrentCallPassup) CurrentCallPassup('D');
4738
4739     break;
4740
4741   /* Remote end has gone away before you answer the call.  Probably your
4742      mother-in-law or banker (which is worse?) ... */
4743   case 0x04:
4744
4745 #ifdef DEBUG
4746     fprintf(stdout, _("Message: Remote end hang up.\n"));
4747     fprintf(stdout, _("   Sequence nr. of the call: %d, error: %i"), MessageBuffer[4],MessageBuffer[6]);
4748
4749     switch (MessageBuffer[6]) {
4750       case 28: fprintf(stdout,_(" (info \"Invalid phone number\")"));break;
4751       case 34: fprintf(stdout,_(" (info \"Network busy\")"));break;
4752       case 42: fprintf(stdout,_(" (info \"Network busy\")"));break;
4753       case 47: fprintf(stdout,_(" (info \"Error in connection\")"));break;
4754       case 50: fprintf(stdout,_(" (info \"Check operator services\")"));break;       case 76: fprintf(stdout,_(" (info \"Check operator services\")"));break;
4755       case 111: fprintf(stdout,_(" (info \"Error in connection\")"));break;
4756     }
4757       
4758     fprintf(stdout,_("\n   For more details with errors see netmonitor manual (test 39) on www.marcin-wiacek.topnet.pl"));
4759     fprintf(stdout,_("\n   If know their meaning, GSM specs decribing them, contact with me on marcin-wiacek@topnet.pl. THX\n"));
4760 #endif /* DEBUG */
4761
4762 #ifndef UCLINUX
4763     CurrentIncomingCall[0] = ' ';
4764 #endif /* UCLINUX */
4765     if (CurrentCallPassup) CurrentCallPassup(' ');
4766
4767     break;
4768
4769   /* Incoming call alert */
4770   case 0x05:
4771
4772 #ifdef DEBUG
4773     fprintf(stdout, _("Message: Incoming call alert:\n"));
4774
4775     /* We can have more then one call ringing - we can distinguish between
4776        them */
4777
4778     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4779     fprintf(stdout, _("   Number: "));
4780
4781     count=MessageBuffer[6];
4782
4783     for (tmp=0; tmp <count; tmp++)
4784       fprintf(stdout, "%c", MessageBuffer[7+tmp]);
4785
4786     fprintf(stdout, "\n");
4787
4788     fprintf(stdout, _("   Name: "));
4789
4790     for (tmp=0; tmp <MessageBuffer[7+count]; tmp++)
4791       fprintf(stdout, "%c", MessageBuffer[8+count+tmp]);
4792
4793     fprintf(stdout, "\n");
4794 #endif /* DEBUG */
4795
4796     count=MessageBuffer[6];
4797
4798 #ifndef UCLINUX
4799     CurrentIncomingCall[0] = 0;
4800     for (tmp=0; tmp <count; tmp++)
4801       sprintf(CurrentIncomingCall, "%s%c", CurrentIncomingCall, MessageBuffer[7+tmp]);
4802 #endif /* UCLINUX */
4803
4804     break;
4805
4806   /* Call answered. Probably your girlfriend...*/
4807   case 0x07:
4808
4809 #ifdef DEBUG
4810     fprintf(stdout, _("Message: Call answered.\n"));
4811     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4812 #endif /* DEBUG */
4813
4814     break;
4815
4816   /* Call ended. Girlfriend is girlfriend, but time is money :-) */
4817   case 0x09:
4818
4819 #ifdef DEBUG
4820     fprintf(stdout, _("Message: Call ended by your phone.\n"));
4821     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4822 #endif /* DEBUG */
4823
4824     break;
4825
4826   /* This message has been seen with the message of subtype 0x09
4827      after I hang the call.
4828
4829   Msg Destination: PC
4830   Msg Source: Phone
4831   Msg Type: 01 
4832   Msg Unknown: 00
4833   Msg Len: 08
4834   Phone: [01 ][08 ][00 ][0a ][04 ][87 ][01 ][42B][1a ][c2 ]
4835
4836   What is the meaning of 87? Can you spell some magic light into
4837   this issue?
4838
4839   */
4840
4841   /* Probably means call over - CK */
4842   case 0x0a:
4843
4844 #ifdef DEBUG
4845     fprintf(stdout, _("Message: Call message, type 0x0a:"));
4846     fprintf(stdout, _("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
4847     fprintf(stdout, _("   Exact meaning not known yet, sorry :-(\n"));
4848 #endif /* DEBUG */
4849
4850 #ifndef UCLINUX
4851     CurrentIncomingCall[0] = ' ';
4852 #endif /* UCLINUX */
4853     if (CurrentCallPassup) CurrentCallPassup(' ');
4854
4855     break;
4856
4857   case 0x40:
4858
4859 #ifdef DEBUG
4860       fprintf(stdout, _("Message: Answer for send DTMF or dial voice command\n"));
4861 #endif
4862
4863 #ifndef UCLINUX
4864     if (CurrentSendDTMFError!=GE_NONE) CurrentSendDTMFError=GE_NONE;
4865 #endif /* UCLINUX */
4866
4867     if (CurrentDialVoiceError!=GE_NONE) CurrentDialVoiceError=GE_NONE;
4868
4869     break;
4870      
4871   default:
4872
4873 #ifdef DEBUG
4874     fprintf(stdout, _("Message: Unknown message of type 0x01\n"));
4875 #endif /* DEBUG */
4876     AppendLogText("Unknown msg\n",false);
4877
4878     break;      /* Visual C Don't like empty cases */
4879   }
4880 }
4881
4882 #ifndef UCLINUX
4883
4884 static void N6110_Dispatch0x03Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
4885
4886   int tmp, count;
4887     
4888   switch (MessageBuffer[3]) {
4889
4890   case 0x04:
4891
4892     /* AFAIK, this frame isn't used anywhere - it's rather for testing :-) */
4893     /* If you want see, if it works with your phone make something like that: */
4894
4895     /* unsigned char connect5[] = {N6110_FRAME_HEADER, 0x03}; */
4896     /* Protocol->SendMessage(4, 0x04, connect5); */
4897
4898     /*                                        Marcin-Wiacek@TopNet.PL */
4899     
4900 #if defined(WIN32) || defined(UCLINUX)
4901     sprintf(Current_IMEI, "%s", MessageBuffer+5);
4902     sprintf(Current_Model, "%s", MessageBuffer+21);
4903     sprintf(Current_Revision, "SW%s, HW%s", MessageBuffer+41, MessageBuffer+35);
4904 #else
4905     snprintf(Current_IMEI, GSM_MAX_IMEI_LENGTH, "%s", MessageBuffer+5);
4906     snprintf(Current_Model, GSM_MAX_MODEL_LENGTH, "%s", MessageBuffer+21);
4907     snprintf(Current_Revision, GSM_MAX_REVISION_LENGTH, "SW%s, HW%s", MessageBuffer+41, MessageBuffer+35);
4908 #endif
4909
4910 #ifdef DEBUG
4911     fprintf(stdout, _("Message: Mobile phone identification received:\n"));
4912     fprintf(stdout, _("   IMEI: %s\n"), Current_IMEI);
4913     fprintf(stdout, _("   Model: %s\n"), Current_Model);
4914     fprintf(stdout, _("   Production Code: %s\n"), MessageBuffer+27);
4915     fprintf(stdout, _("   HW: %s\n"), MessageBuffer+35);
4916     fprintf(stdout, _("   Firmware: %s\n"), MessageBuffer+41);
4917 #endif /* DEBUG */
4918
4919     break;
4920
4921   /* Get group data */    
4922   /* [ID],[name_len],[name].,[ringtone],[graphicon],[lenhi],[lenlo],[bitmap] */
4923   case 0x11:   
4924  
4925     if (CurrentGetBitmap!=NULL) {
4926       if (CurrentGetBitmap->number==MessageBuffer[4]) {
4927         count=MessageBuffer[5];
4928         memcpy(CurrentGetBitmap->text,MessageBuffer+6,count);
4929         CurrentGetBitmap->text[count]=0;
4930
4931 #ifdef DEBUG    
4932         fprintf(stdout, _("Message: Caller group datas\n"));
4933         fprintf(stdout, _("Caller group name: %s\n"),CurrentGetBitmap->text);
4934 #endif /* DEBUG */
4935
4936         count+=6;
4937
4938         CurrentGetBitmap->ringtone=MessageBuffer[count++];
4939 #ifdef DEBUG    
4940         fprintf(stdout, _("Caller group ringtone ID: %i"),CurrentGetBitmap->ringtone);
4941         if (CurrentGetBitmap->ringtone==16) fprintf(stdout,_(" (default)"));
4942         fprintf(stdout,_("\n"));
4943 #endif /* DEBUG */
4944
4945         CurrentGetBitmap->enabled=(MessageBuffer[count++]==1);
4946 #ifdef DEBUG    
4947         fprintf(stdout, _("Caller group logo "));
4948         if (CurrentGetBitmap->enabled)
4949           fprintf(stdout, _("enabled \n"));
4950         else
4951           fprintf(stdout, _("disabled \n"));
4952 #endif /* DEBUG */      
4953
4954         CurrentGetBitmap->size=MessageBuffer[count++]<<8;
4955         CurrentGetBitmap->size+=MessageBuffer[count++];
4956 #ifdef DEBUG    
4957         fprintf(stdout, _("Bitmap size=%i\n"),CurrentGetBitmap->size);
4958 #endif /* DEBUG */
4959
4960         count++;
4961         CurrentGetBitmap->width=MessageBuffer[count++];
4962         CurrentGetBitmap->height=MessageBuffer[count++];
4963         count++;
4964         tmp=CurrentGetBitmap->height*CurrentGetBitmap->width/8;
4965         if (CurrentGetBitmap->size>tmp) CurrentGetBitmap->size=tmp;
4966         memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count,CurrentGetBitmap->size);
4967         CurrentGetBitmapError=GE_NONE;
4968       } else {
4969 #ifdef DEBUG    
4970         fprintf(stdout, _("Message: Caller group datas received, but group number does not match (%i is not %i)\n"),MessageBuffer[4],CurrentGetBitmap->number);
4971 #endif
4972       }
4973     } else {
4974 #ifdef DEBUG
4975       fprintf(stdout, _("Message: Caller group data received but not requested!\n"));
4976 #endif
4977     }
4978     break;
4979
4980   /* Get group data error */
4981   case 0x12:   
4982       
4983     CurrentGetBitmapError=GE_UNKNOWN;   
4984 #ifdef DEBUG
4985     fprintf(stdout, _("Message: Error attempting to get caller group data.\n"));
4986 #endif   
4987     break;
4988
4989   /* Set group data OK */      
4990   case 0x14:   
4991       
4992     CurrentSetBitmapError=GE_NONE;      
4993 #ifdef DEBUG
4994     fprintf(stdout, _("Message: Caller group data set correctly.\n"));
4995 #endif
4996     break;
4997
4998   /* Set group data error */
4999   case 0x15:   
5000       
5001     CurrentSetBitmapError=GE_UNKNOWN;      
5002 #ifdef DEBUG
5003     fprintf(stdout, _("Message: Error attempting to set caller group data\n"));
5004 #endif
5005     break;  
5006   
5007   default:
5008
5009 #ifdef DEBUG
5010     fprintf(stdout, _("Message: Unknown message of type 0x03\n"));
5011 #endif /* DEBUG */
5012     AppendLogText("Unknown msg\n",false);
5013
5014     break;      /* Visual C Don't like empty cases */
5015   }
5016 }
5017
5018 static void N6110_Dispatch0x05Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5019
5020   int tmp, count, length;
5021   bool issupported;
5022
5023 #ifdef DEBUG
5024   int i;
5025 #endif
5026
5027   switch (MessageBuffer[3]) {
5028
5029   /* Startup Logo */
5030   case 0x17:  
5031
5032 #ifdef DEBUG
5033     fprintf(stdout, _("Message: Startup Logo, welcome note and dealer welcome note received.\n"));
5034 #endif
5035
5036     if (CurrentGetBitmap!=NULL) {
5037        
5038       issupported=false;
5039        
5040       count=5;
5041        
5042       for (tmp=0;tmp<MessageBuffer[4];tmp++){
5043         switch (MessageBuffer[count++]) {
5044         case 0x01:
5045           if (CurrentGetBitmap->type==GSM_StartupLogo) {
5046             CurrentGetBitmap->height=MessageBuffer[count++];
5047             CurrentGetBitmap->width=MessageBuffer[count++];
5048             CurrentGetBitmap->size=CurrentGetBitmap->height*CurrentGetBitmap->width/8;
5049             length=CurrentGetBitmap->size;
5050             memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count,length);
5051           } else {
5052             length=MessageBuffer[count++];
5053             length=length*MessageBuffer[count++]/8;
5054           }
5055           count+=length;
5056 #ifdef DEBUG
5057           fprintf(stdout, _("Startup logo supported - "));
5058           if (length!=0) { fprintf(stdout, _("currently set\n"));   }
5059                     else { fprintf(stdout, _("currently empty\n")); }
5060 #endif
5061           if (CurrentGetBitmap->type==GSM_StartupLogo) issupported=true;
5062           break;
5063         case 0x02:
5064           length=MessageBuffer[count];
5065           if (CurrentGetBitmap->type==GSM_WelcomeNoteText) {
5066             memcpy(CurrentGetBitmap->text,MessageBuffer+count+1,length);
5067             CurrentGetBitmap->text[length]=0;
5068           }
5069 #ifdef DEBUG
5070           fprintf(stdout, _("Startup Text supported - "));
5071           if (length!=0)
5072           {
5073             fprintf(stdout, _("currently set to \""));
5074             for (i=0;i<length;i++) fprintf(stdout, _("%c"),MessageBuffer[count+1+i]);
5075             fprintf(stdout, _("\"\n"));
5076           } else {
5077             fprintf(stdout, _("currently empty\n"));
5078           }
5079 #endif
5080           count+=length+1;
5081           if (CurrentGetBitmap->type==GSM_WelcomeNoteText) issupported=true;
5082           break;
5083         case 0x03:
5084           length=MessageBuffer[count];
5085           if (CurrentGetBitmap->type==GSM_DealerNoteText) {
5086             memcpy(CurrentGetBitmap->text,MessageBuffer+count+1,length);
5087             CurrentGetBitmap->text[length]=0;
5088           }
5089 #ifdef DEBUG
5090           fprintf(stdout, _("Dealer Welcome supported - "));
5091           if (length!=0)
5092           {
5093             fprintf(stdout, _("currently set to \""));
5094             for (i=0;i<length;i++) fprintf(stdout, _("%c"),MessageBuffer[count+1+i]);
5095             fprintf(stdout, _("\"\n"));
5096           } else {
5097             fprintf(stdout, _("currently empty\n"));
5098           }
5099 #endif
5100           count+=length+1;
5101           if (CurrentGetBitmap->type==GSM_DealerNoteText) issupported=true;
5102           break;
5103         }
5104       }
5105       if (issupported) CurrentGetBitmapError=GE_NONE;
5106                   else CurrentGetBitmapError=GE_NOTSUPPORTED;
5107     } else {
5108 #ifdef DEBUG
5109       fprintf(stdout, _("Message: Startup logo received but not requested!\n"));
5110 #endif
5111     }
5112     break;
5113
5114   /* Set startup OK */
5115   case 0x19:   
5116     
5117     CurrentSetBitmapError=GE_NONE;    
5118 #ifdef DEBUG
5119     fprintf(stdout, _("Message: Startup logo, welcome note or dealer welcome note correctly set.\n"));
5120 #endif  
5121     break;      
5122
5123   /* Set Operator Logo OK */
5124   case 0x31:   
5125       
5126 #ifdef DEBUG
5127     fprintf(stdout, _("Message: Operator logo correctly set.\n"));
5128 #endif  
5129
5130     CurrentSetBitmapError=GE_NONE;      
5131     break;
5132
5133   /* Set Operator Logo Error */      
5134   case 0x32:  
5135       
5136 #ifdef DEBUG
5137     fprintf(stdout, _("Message: Error setting operator logo!\n"));
5138 #endif
5139
5140     CurrentSetBitmapError=GE_UNKNOWN;        
5141     break;
5142
5143   /* Operator Logo */
5144   /* [location],[netcode x 3],[lenhi],[lenlo],[bitmap] */ 
5145   case 0x34:
5146  
5147     if (CurrentGetBitmap!=NULL) {
5148
5149       count=5;  /* Location ignored. */
5150
5151       DecodeNetworkCode(MessageBuffer+count, CurrentGetBitmap->netcode);
5152       count=count+3;
5153
5154 #ifdef DEBUG
5155       fprintf(stdout, _("Message: Operator Logo for %s (%s) network received.\n"),
5156                            CurrentGetBitmap->netcode,
5157                            GSM_GetNetworkName(CurrentGetBitmap->netcode));
5158 #endif  
5159
5160       CurrentGetBitmap->size=MessageBuffer[count++]<<8;
5161       CurrentGetBitmap->size+=MessageBuffer[count++];
5162       count++;
5163       CurrentGetBitmap->width=MessageBuffer[count++];
5164       CurrentGetBitmap->height=MessageBuffer[count++];
5165       count++;
5166       tmp=CurrentGetBitmap->height*CurrentGetBitmap->width/8;
5167       if (CurrentGetBitmap->size>tmp) CurrentGetBitmap->size=tmp;
5168       memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count,CurrentGetBitmap->size);
5169       CurrentGetBitmapError=GE_NONE;
5170     } else {
5171 #ifdef DEBUG
5172       fprintf(stdout, _("Message: Operator logo received but not requested!\n"));
5173 #endif
5174     }
5175       
5176     break;
5177
5178   /* Get op logo error */      
5179   case 0x35:
5180      
5181 #ifdef DEBUG
5182     fprintf(stdout, _("Message: Error getting operator logo!\n"));
5183 #endif  
5184     CurrentGetBitmapError=GE_UNKNOWN; 
5185     break;
5186
5187   default:
5188
5189 #ifdef DEBUG
5190     fprintf(stdout, _("Message: Unknown message of type 0x05\n"));
5191 #endif /* DEBUG */
5192     AppendLogText("Unknown msg\n",false);
5193
5194     break;
5195   }
5196 }
5197
5198 static void N6110_Dispatch0x06Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5199
5200   int tmp;
5201   unsigned char output[160];
5202
5203 #ifdef DEBUG
5204   int i;
5205 #endif
5206     
5207   switch (MessageBuffer[3]) {
5208
5209   case 0x05:
5210
5211     /* MessageBuffer[3] = 0x05
5212        MessageBuffer[4] = 0x00
5213        MessageBuffer[5] = 0x0f
5214        MessageBuffer[6] = 0x03
5215        MessageBuffer[7] = length of packed message
5216
5217        This is all I have seen - Gerry Anderson */
5218
5219     tmp=GSM_UnpackEightBitsToSeven(0, 82, 82, MessageBuffer+8, output);
5220
5221 #ifdef DEBUG
5222
5223     fprintf(stdout, _("Message from Network operator: "));
5224
5225     for (i=0; i<tmp; i++)
5226        fprintf(stdout, "%c", DecodeWithDefaultAlphabet(output[i]));
5227
5228     fprintf(stdout, "\n");
5229
5230 #endif /* DEBUG */
5231
5232     break;
5233
5234   default:
5235
5236 #ifdef DEBUG
5237     fprintf(stdout, _("Message: Unknown message of type 0x06\n"));
5238 #endif /* DEBUG */
5239     AppendLogText("Unknown msg\n",false);
5240
5241     break;
5242   }
5243 }
5244
5245 static void N6110_Dispatch0x09Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5246     
5247   switch (MessageBuffer[3]) {
5248     
5249   case 0x80:    
5250 #ifdef DEBUG
5251     fprintf(stdout, _("Message: SIM card login\n"));
5252 #endif
5253     break;
5254
5255   case 0x81:    
5256 #ifdef DEBUG
5257     fprintf(stdout, _("Message: SIM card logout\n"));
5258 #endif
5259     break;
5260       
5261   default:
5262 #ifdef DEBUG
5263     fprintf(stdout, _("Unknown message of type 0x09.\n"));      
5264 #endif
5265     AppendLogText("Unknown msg\n",false);
5266     break;
5267   }
5268 }
5269
5270 static void N6110_Dispatch0x13Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5271
5272   switch(MessageBuffer[3]) {
5273     
5274   case 0x6a:
5275
5276 #ifdef DEBUG
5277     fprintf(stdout, _("Message: Calendar Alarm active\n"));
5278     fprintf(stdout, _("   Item number: %d\n"), MessageBuffer[4]);
5279 #endif /* DEBUG */
5280
5281   default:
5282 #ifdef DEBUG
5283     fprintf(stdout, _("Unknown message of type 0x13.\n"));      
5284 #endif
5285     AppendLogText("Unknown msg\n",false);
5286     break;
5287   }
5288 }
5289
5290 #endif /* UCLINUX */
5291
5292 void N6110_Dispatch0x40Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5293
5294   int i;
5295   
5296   switch(MessageBuffer[2]) {
5297
5298   case 0x02:
5299
5300 #ifdef DEBUG
5301     fprintf(stdout, _("Message: ACK for simlock opening part 1\n"));
5302 #endif /* DEBUG */
5303     
5304     CurrentMagicError=GE_NONE;
5305     break;
5306     
5307   case 0x7c:
5308
5309 #ifdef DEBUG
5310     fprintf(stdout, _("Message: Answer for call commands.\n"));
5311 #endif
5312     
5313     CurrentDialVoiceError=GE_NONE;      
5314     break;
5315       
5316   case 0x81:
5317
5318 #ifdef DEBUG
5319     fprintf(stdout, _("Message: ACK for simlock opening part 2\n"));
5320 #endif /* DEBUG */
5321     
5322     CurrentMagicError=GE_NONE;
5323     break;
5324
5325   case 0x82:
5326
5327 #ifdef DEBUG
5328       fprintf(stdout, _("Message: ACK for simlock closing\n"));
5329 #endif /* DEBUG */
5330     
5331     CurrentMagicError=GE_NONE;
5332     break;
5333
5334   case 0xd4:
5335
5336     switch (MessageBuffer[5]) {
5337       case 0xa0:
5338 #ifdef DEBUG
5339         fprintf(stdout,_("Message: EEPROM contest received\n"));
5340 #endif
5341
5342         if (MessageBuffer[8]!=0x00) {
5343           for (i=9;i<MessageLength;i++) {
5344             fprintf(stdout,_("%c"), MessageBuffer[i]);
5345         }
5346
5347         CurrentMagicError=GE_NONE;
5348       }
5349       
5350       break;
5351     }
5352       
5353 #ifdef DEBUG
5354     fprintf(stdout, _("Unknown message of type 0x40.\n"));
5355 #endif /* DEBUG */
5356     AppendLogText("Unknown msg\n",false);      
5357     break;
5358
5359 #ifndef UCLINUX
5360   case 0xcf:
5361
5362     N6110_DisplayTestsInfo(MessageBuffer);
5363     break;
5364 #endif /* UCLINUX */
5365       
5366   default:
5367
5368 #ifdef DEBUG
5369     fprintf(stdout, _("Unknown message of type 0x40.\n"));
5370 #endif /* DEBUG */
5371     AppendLogText("Unknown msg\n",false);
5372     break;      /* Visual C Don't like empty cases */
5373   }
5374 }
5375
5376 #ifndef UCLINUX
5377
5378 static void N6110_Dispatch0x47Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5379
5380   int count;
5381   
5382   switch(MessageBuffer[3]) {
5383     
5384   case 0x02:
5385
5386     count=5;
5387     
5388     if (MessageBuffer[5]!=0) {
5389       strcpy(CurrentGetBitmap->Sender,GSM_UnpackSemiOctetNumber(MessageBuffer+5,true));
5390
5391       while (MessageBuffer[count]!=0) {
5392         count++;
5393       }
5394
5395       count++;
5396     } else {
5397       strcpy(CurrentGetBitmap->Sender,"\0");
5398
5399       count+=3;
5400     }
5401
5402     memcpy(CurrentGetBitmap->text,MessageBuffer+count+1,MessageBuffer[count]);
5403     CurrentGetBitmap->text[MessageBuffer[count]]=0;
5404
5405     if (MessageBuffer[count]!=0)
5406       count+=MessageBuffer[count];
5407
5408     count++;
5409
5410 #ifdef DEBUG
5411     fprintf(stdout,_("Picture Image received, text \"%s\", sender %s\n"),CurrentGetBitmap->text,CurrentGetBitmap->Sender);
5412 #endif
5413
5414     CurrentGetBitmap->width=MessageBuffer[count+1];
5415     CurrentGetBitmap->height=MessageBuffer[count+2]; 
5416     CurrentGetBitmap->size=CurrentGetBitmap->height*CurrentGetBitmap->width/8;
5417       
5418     memcpy(CurrentGetBitmap->bitmap,MessageBuffer+count+4,CurrentGetBitmap->size);
5419       
5420     CurrentGetBitmapError=GE_NONE;
5421     break;
5422
5423   case 0x04:
5424
5425 #ifdef DEBUG
5426     fprintf(stdout,_("Getting or setting Picture Image - OK\n"));
5427 #endif
5428     CurrentSetBitmapError=GE_NONE;
5429     CurrentGetBitmapError=GE_NONE;
5430     break;      
5431
5432   case 0x05:
5433
5434 #ifdef DEBUG
5435     fprintf(stdout,_("Setting Picture Image - invalid location or other error\n"));
5436 #endif
5437     CurrentSetBitmapError=GE_UNKNOWN;
5438     break;      
5439
5440   case 0x06:
5441
5442 #ifdef DEBUG
5443     fprintf(stdout,_("Getting Picture Image - invalid location or other error\n"));
5444 #endif
5445     CurrentGetBitmapError=GE_UNKNOWN;
5446     break;      
5447
5448   default:
5449
5450 #ifdef DEBUG
5451     fprintf(stdout, _("Unknown message of type 0x47.\n"));
5452 #endif /* DEBUG */
5453     AppendLogText("Unknown msg\n",false);
5454     break;      /* Visual C Don't like empty cases */
5455   }
5456 }
5457
5458 #endif /* UCLINUX */
5459
5460 void N6110_DispatchACKMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5461   char buffer[50];
5462   
5463   sprintf(buffer,"Received ACK %02x %02x\n",MessageBuffer[0],MessageBuffer[1]);
5464   AppendLog(buffer,strlen(buffer),false);
5465
5466 #ifdef DEBUG
5467   fprintf(stdout, _("[Received Ack of type %02x, seq: %2x]\n"), MessageBuffer[0],
5468                                                                 MessageBuffer[1]);
5469 #endif /* DEBUG */
5470   
5471   CurrentLinkOK = true;
5472 }
5473
5474 static void N6110_Dispatch0xD0Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5475    
5476 #ifdef DEBUG
5477   fprintf(stdout, _("Message: The phone is powered on - seq 1.\n"));
5478 #endif /* DEBUG */
5479
5480 }
5481
5482 /* This function is used for parsing the RLP frame into fields. */
5483 void N6110_RX_HandleRLPMessage(u8 *MessageBuffer)
5484 {
5485
5486   RLP_F96Frame frame;
5487   int count;
5488   int valid = true;
5489
5490   /* We do not need RLP frame parsing to be done when we do not have callback
5491      specified. */
5492   if (CurrentRLP_RXCallback == NULL)
5493     return;
5494     
5495   /* Anybody know the official meaning of the first two bytes?
5496      Nokia 6150 sends junk frames starting D9 01, and real frames starting
5497      D9 00. We'd drop the junk frames anyway because the FCS is bad, but
5498      it's tidier to do it here. We still need to call the callback function
5499      to give it a chance to handle timeouts and/or transmit a frame */
5500   if (MessageBuffer[0] == 0xd9 && MessageBuffer[1] == 0x01)
5501     valid = false;
5502
5503   /* Nokia uses 240 bit frame size of RLP frames as per GSM 04.22
5504      specification, so Header consists of 16 bits (2 bytes). See section 4.1
5505      of the specification. */
5506     
5507   frame.Header[0] = MessageBuffer[2];
5508   frame.Header[1] = MessageBuffer[3];
5509
5510   /* Next 200 bits (25 bytes) contain the Information. We store the
5511      information in the Data array. */
5512
5513   for (count = 0; count < 25; count ++)
5514     frame.Data[count] = MessageBuffer[4 + count];
5515
5516   /* The last 24 bits (3 bytes) contain FCS. */
5517
5518   frame.FCS[0] = MessageBuffer[29];
5519   frame.FCS[1] = MessageBuffer[30];
5520   frame.FCS[2] = MessageBuffer[31];
5521
5522   /* Here we pass the frame down in the input stream. */
5523   CurrentRLP_RXCallback(valid ? &frame : NULL);
5524 }
5525
5526 static void N6110_Dispatch0xF4Message(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5527
5528 #ifdef DEBUG
5529   fprintf(stdout, _("Message: The phone is powered on - seq 2.\n"));
5530 #endif /* DEBUG */
5531
5532 }
5533
5534 #ifndef UCLINUX
5535
5536 void N6110_ReplyIncomingSMS(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5537
5538   GSM_SMSMessage NullSMS;
5539
5540   switch (MessageBuffer[6]) {
5541
5542     case 0x00: NullSMS.Type = GST_SMS; NullSMS.folder = GST_INBOX; break;
5543     case 0x01: NullSMS.Type = GST_DR;  NullSMS.folder = GST_INBOX; break;
5544
5545     /* Is it possible ? */
5546     case 0x02: NullSMS.Type = GST_SMS; NullSMS.folder = GST_OUTBOX; break;      
5547     default:   NullSMS.Type = GST_UN;                               break;
5548   }
5549
5550 #ifdef DEBUG
5551   if (NullSMS.Type == GST_DR)
5552     fprintf(stdout, _("Message: SMS Message (Report) Received\n"));
5553   else 
5554     fprintf(stdout, _("Message: SMS Message Received\n"));  
5555 #endif /* DEBUG */
5556
5557   GSM_DecodeNokiaSMSFrame(&NullSMS, MessageBuffer+7, MessageLength-7);
5558
5559 #ifdef DEBUG
5560   fprintf(stdout, _("\n"));      
5561 #endif /* DEBUG */
5562 }
5563
5564 #endif /* UCLINUX */
5565
5566 void N6110_DispatchMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
5567
5568   bool unknown=false;
5569
5570   /* Switch on the basis of the message type byte */
5571   switch (MessageType) {
5572           
5573   /* Call information */
5574   case 0x01:
5575
5576     N6110_Dispatch0x01Message(MessageLength, MessageBuffer, MessageType);
5577     break;
5578
5579 #ifndef UCLINUX
5580   /* SMS handling */
5581   case 0x02:
5582     switch (MessageBuffer[3]) {
5583       case 0x02:
5584       case 0x03:N6110_ReplySendSMSMessage(MessageLength,MessageBuffer,MessageType);break;
5585       case 0x10:N6110_ReplyIncomingSMS(MessageLength,MessageBuffer,MessageType);break;
5586       case 0x21:N6110_ReplySetCellBroadcast(MessageLength, MessageBuffer, MessageType);break;
5587       case 0x23:N6110_ReplyReadCellBroadcast(MessageLength, MessageBuffer, MessageType);break;
5588       case 0x31:N6110_ReplySetSMSCenter(MessageLength,MessageBuffer,MessageType);break;
5589       case 0x34:
5590       case 0x35:N6110_ReplyGetSMSCenter(MessageLength,MessageBuffer,MessageType);break;
5591       default  :unknown=true;break;
5592     }
5593     break;
5594 #endif /* UCLINUX */
5595
5596   /* Phonebook handling */
5597   case 0x03:
5598     switch (MessageBuffer[3]) {
5599       case 0x02:
5600       case 0x03:N6110_ReplyGetMemoryLocation(MessageLength,MessageBuffer,MessageType);break;
5601       case 0x05:
5602       case 0x06:N6110_ReplyWritePhonebookLocation(MessageLength,MessageBuffer,MessageType);break;
5603       case 0x08:
5604       case 0x09:N6110_ReplyGetMemoryStatus(MessageLength,MessageBuffer,MessageType);break;
5605       case 0x17:
5606       case 0x18:N6110_ReplyGetSpeedDial(MessageLength,MessageBuffer,MessageType);break;
5607       case 0x1a:
5608       case 0x1b:N6110_ReplySetSpeedDial(MessageLength,MessageBuffer,MessageType);break;
5609 #ifndef UCLINUX
5610       default  :N6110_Dispatch0x03Message(MessageLength,MessageBuffer,MessageType);break;
5611 #endif /* UCLINUX */
5612     }
5613     break;
5614
5615   /* Phone status */     
5616   case 0x04:
5617     switch (MessageBuffer[3]) {
5618       case 0x02:N6110_ReplyRFBatteryLevel(MessageLength,MessageBuffer,MessageType);break;
5619       default  :unknown=true;break;
5620     }
5621     break;
5622       
5623 #ifndef UCLINUX
5624   /* Startup Logo, Operator Logo and Profiles. */
5625   case 0x05:
5626     switch (MessageBuffer[3]) {
5627       case 0x11:N6110_ReplySetProfile    (MessageLength,MessageBuffer,MessageType);break;
5628       case 0x14:N6110_ReplyGetProfile    (MessageLength,MessageBuffer,MessageType);break;
5629       case 0x1b:N6110_ReplyGetProfile    (MessageLength,MessageBuffer,MessageType);break;
5630       case 0x1d:N6110_ReplySetProfile    (MessageLength,MessageBuffer,MessageType);break;
5631       case 0x37:N6110_ReplySetRingtone   (MessageLength,MessageBuffer,MessageType);break;
5632       case 0x38:N6110_ReplySetRingtone   (MessageLength,MessageBuffer,MessageType);break;
5633       default  :N6110_Dispatch0x05Message(MessageLength,MessageBuffer,MessageType);break;
5634     }
5635     break;
5636
5637   /* Network Operator Message to handset -> Gerry Anderson & prepaid info */
5638   /* Call diverts */
5639   case 0x06:
5640     switch (MessageBuffer[3]) {
5641       case 0x02:
5642       case 0x03:N6110_ReplyCallDivert    (MessageLength,MessageBuffer,MessageType);break;
5643       default  :N6110_Dispatch0x06Message(MessageLength,MessageBuffer,MessageType);break;
5644     }
5645     break;
5646
5647   /* Security code requests */
5648   case 0x08:
5649     switch (MessageBuffer[3]) {
5650       case 0x08:N6110_ReplyGetSecurityCodeStatus(MessageLength,MessageBuffer,MessageType);break;
5651       case 0x0b:N6110_ReplyEnterSecurityCode    (MessageLength,MessageBuffer,MessageType);break;
5652       default  :N6110_ReplyEnterSecurityCode    (MessageLength,MessageBuffer,MessageType);break;
5653     }
5654     break;
5655
5656   /* SIM login */
5657   case 0x09:
5658
5659     N6110_Dispatch0x09Message(MessageLength, MessageBuffer, MessageType);
5660     break;
5661
5662   /* Network info */
5663   case 0x0a:
5664     switch (MessageBuffer[3]) {
5665       case 0x71:N6110_ReplyGetNetworkInfo(MessageLength,MessageBuffer,MessageType);break;
5666       default  :unknown=true;break;
5667     }
5668     break;
5669
5670   /* Simulating key pressing */
5671   case 0x0c:
5672     switch (MessageBuffer[3]) {
5673       case 0x43:N6110_ReplyPressKey(MessageLength,MessageBuffer,MessageType);break;
5674       default  :unknown=true;break;
5675     }
5676     break;
5677
5678   /* Display */
5679   case 0x0d:
5680     switch (MessageBuffer[3]) {
5681       case 0x50:N6110_ReplyDisplayOutput   (MessageLength,MessageBuffer,MessageType);break;
5682       case 0x52:N6110_ReplyGetDisplayStatus(MessageLength,MessageBuffer,MessageType);break;
5683       case 0x54:N6110_ReplyDisplayOutput   (MessageLength,MessageBuffer,MessageType);break;
5684       default  :unknown=true;break;
5685     }
5686     break;
5687
5688   /* Phone Clock and Alarm */
5689   case 0x11:
5690     switch (MessageBuffer[3]) {
5691       case 0x61:N6110_ReplySetDateTime(MessageLength,MessageBuffer,MessageType);break;
5692       case 0x63:N6110_ReplyGetDateTime(MessageLength,MessageBuffer,MessageType);break;
5693       case 0x6c:N6110_ReplySetAlarm   (MessageLength,MessageBuffer,MessageType);break;
5694       case 0x6e:N6110_ReplyGetAlarm   (MessageLength,MessageBuffer,MessageType);break;
5695       default  :unknown=true;break;
5696     }
5697     break;
5698
5699   /* Calendar notes handling */
5700   case 0x13:
5701     switch (MessageBuffer[3]) {
5702       case 0x65:N6110_ReplyWriteCalendarNote (MessageLength,MessageBuffer,MessageType);break;
5703       case 0x67:N6110_ReplyGetCalendarNote   (MessageLength,MessageBuffer,MessageType);break;
5704       case 0x69:N6110_ReplyDeleteCalendarNote(MessageLength,MessageBuffer,MessageType);break;
5705       default  :N6110_Dispatch0x13Message    (MessageLength,MessageBuffer,MessageType);break;
5706     }
5707     break;
5708
5709   /* SMS Messages */
5710   case 0x14:
5711     switch (MessageBuffer[3]) {
5712       case 0x05:
5713       case 0x06:N6110_ReplySaveSMSMessage  (MessageLength,MessageBuffer,MessageType);break;
5714       case 0x08:
5715       case 0x09:N6110_ReplyGetSMSMessage   (MessageLength,MessageBuffer,MessageType);break;
5716       case 0x0b:N6110_ReplyDeleteSMSMessage(MessageLength,MessageBuffer,MessageType);break;
5717       case 0x37:
5718       case 0x38:N6110_ReplyGetSMSStatus    (MessageLength,MessageBuffer,MessageType);break;
5719       default  :unknown=true;break;
5720     }
5721     break;
5722
5723   /* WAP */
5724   case 0x3f:
5725     switch (MessageBuffer[3]) {
5726       case 0x01:
5727       case 0x02:N7110_ReplyEnableWAPCommands(MessageLength,MessageBuffer,MessageType);break;
5728       case 0x07:
5729       case 0x08:N7110_ReplyGetWAPBookmark   (MessageLength,MessageBuffer,MessageType);break;
5730       case 0x0a:
5731       case 0x0b:N7110_ReplySetWAPBookmark   (MessageLength,MessageBuffer,MessageType);break;
5732       case 0x16:
5733       case 0x17:
5734       case 0x1c:N7110_ReplyGetWAPSettings   (MessageLength,MessageBuffer,MessageType);break;
5735       default  :unknown=true;break;
5736     }
5737     break;
5738 #endif /* UCLINUX */
5739
5740   /* Internal phone functions? */
5741   case 0x40:
5742     switch (MessageBuffer[2]) {
5743       case 0x64:N6110_ReplyEnableExtendedCommands  (MessageLength,MessageBuffer,MessageType);break;
5744 #ifndef UCLINUX
5745       case 0x65:N6110_ReplyResetPhoneSettings      (MessageLength,MessageBuffer,MessageType);break;
5746 #endif /* UCLINUX */
5747       case 0x66:N6110_ReplyIMEI                    (MessageLength,MessageBuffer,MessageType);break;
5748 #ifndef UCLINUX
5749       case 0x6a:N6110_ReplyGetProductProfileSetting(MessageLength,MessageBuffer,MessageType);break;
5750       case 0x6b:N6110_ReplySetProductProfileSetting(MessageLength,MessageBuffer,MessageType);break;
5751       case 0x6e:N6110_ReplyGetSecurityCode         (MessageLength,MessageBuffer,MessageType);break;
5752       case 0x7e:N6110_ReplyNetmonitor              (MessageLength,MessageBuffer,MessageType);break;
5753       case 0x8a:N6110_ReplySimlockInfo             (MessageLength,MessageBuffer,MessageType);break;
5754       case 0x8b:N6110_ReplySetOperatorName         (MessageLength,MessageBuffer,MessageType);break;
5755       case 0x8c:N6110_ReplyGetOperatorName         (MessageLength,MessageBuffer,MessageType);break;
5756       case 0x8f:N6110_ReplyPlayTone                (MessageLength,MessageBuffer,MessageType);break;
5757       case 0x9e:N6110_ReplyGetBinRingtone          (MessageLength,MessageBuffer,MessageType);break;
5758       case 0xa0:N6110_ReplySetBinRingtone          (MessageLength,MessageBuffer,MessageType);break;
5759 #endif /* UCLINUX */
5760       case 0xc8:N6110_ReplyHW                      (MessageLength,MessageBuffer,MessageType);break;
5761       default  :N6110_Dispatch0x40Message          (MessageLength,MessageBuffer,MessageType);break;
5762     }
5763     break;
5764
5765 #ifndef UCLINUX
5766   /* Picture Images */
5767   case 0x47:
5768
5769     N6110_Dispatch0x47Message(MessageLength, MessageBuffer, MessageType);
5770     break;
5771 #endif /* UCLINUX */
5772
5773   /* Mobile phone identification */
5774   case 0x64:
5775
5776     N6110_ReplyGetAuthentication(MessageLength, MessageBuffer, MessageType);
5777     break;
5778
5779   /***** Acknowlegment of our frames. *****/
5780   case FBUS_FRTYPE_ACK:
5781
5782     N6110_DispatchACKMessage(MessageLength, MessageBuffer, MessageType);
5783     break;
5784
5785   /***** Power on message. *****/
5786   case 0xd0:
5787
5788     N6110_Dispatch0xD0Message(MessageLength, MessageBuffer, MessageType);
5789     break;
5790
5791   case 0xd2:
5792
5793     N6110_ReplyID(MessageLength, MessageBuffer, MessageType);
5794     break;
5795   
5796   /***** RLP frame received. *****/
5797   case 0xf1:
5798
5799     N6110_RX_HandleRLPMessage(MessageBuffer);
5800     break;
5801
5802   /***** Power on message. *****/
5803   case 0xf4:
5804
5805     N6110_Dispatch0xF4Message(MessageLength, MessageBuffer, MessageType);
5806     break;
5807
5808   /***** Unknown message *****/
5809   /* If you think that you know the exact meaning of other messages - please
5810      let us know. */
5811   default:
5812
5813 #ifdef DEBUG
5814     fprintf(stdout, _("Message: Unknown message type.\n"));
5815 #endif /* DEBUG */
5816     AppendLogText("Unknown msg type\n",false);
5817
5818     unknown=false;
5819     break;
5820
5821   }
5822
5823   if (unknown) {
5824 #ifdef DEBUG
5825     fprintf(stdout, _("Unknown message of type %02x.\n"),MessageType);
5826 #endif
5827     AppendLogText("Unknown msg\n",false);
5828   }
5829 }