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