7033493d92c2a8ac38bc521adb05c6f20c6d77d6
[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 #if 0
2584         unsigned char req2[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x01,
2585                                      0x07,0xa2,0xc8,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
2586                                      0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80,0x01,0x60 };
2587 #endif
2588         unsigned char req3[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x01,
2589                                      0x07,0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
2590                                      0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80 };
2591         unsigned char req4[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x81,
2592                                      0x07,0xa1,0x88,0x89,0x21,0x15,0x63,0xa0,0x00,0x06,
2593                                      0x88,0x90,0x21,0x48,0x40,0xbb,0x07,0xa3,0xb8,0x81,
2594                                      0x20,0x15,0x63,0x80 };
2595
2596         int i = 0;
2597         u8 size;
2598
2599         CurrentCallPassup=callpassup;
2600
2601         switch (type) {
2602         case 0:
2603                 usleep(100); Protocol->SendMessage(sizeof(req3), 0x01, req3);   /* Lace */
2604                 usleep(100);
2605                 req_end = req_end0;
2606                 size = sizeof(req_end0);
2607                 break;
2608         case 1:
2609                 Protocol->SendMessage(sizeof(req3), 0x01, req3);
2610                 usleep(1000000);
2611                 Protocol->SendMessage(sizeof(req4), 0x01, req4);
2612                 usleep(1000000);
2613                 req_end = req_end1;
2614                 size = sizeof(req_end1);
2615                 break;
2616         case -1:   /* Just used to set the call passup */
2617                 return GE_NONE;
2618                 break;
2619         default:
2620                 req_end = req_end0;
2621                 size = sizeof(req_end0);
2622                 break;
2623         }
2624
2625         req[4] = strlen(Number);
2626
2627         for(i = 0; i < strlen(Number) ; i++)
2628                 req[5+i] = Number[i];
2629
2630         memcpy(req + 5 + strlen(Number), req_end, size);
2631
2632         Protocol->SendMessage(5 + size + strlen(Number), 0x01, req);
2633         usleep(1000000);
2634
2635 #if 0
2636         if (type != 1) Protocol->SendMessage(26, 0x01, req2);
2637 #endif
2638
2639         return (GE_NONE);
2640 }
2641
2642 #ifndef UCLINUX
2643
2644 GSM_Error N6110_GetIncomingCallNr(char *Number)
2645 {
2646
2647   if (*CurrentIncomingCall != ' ') {
2648     strcpy(Number, CurrentIncomingCall);
2649     return GE_NONE;
2650   }
2651   else
2652     return GE_BUSY;
2653 }
2654
2655 #endif /* UCLINUX */
2656
2657 GSM_Error N6110_CancelCall(void)
2658 {
2659 //  This frame & method works only on 61xx/51xx
2660 //  unsigned char req[] = { N6110_FRAME_HEADER, 0x08, 0x00, 0x85};
2661 //  req[4]=CurrentCallSequenceNumber;
2662 //  Protocol->SendMessage(6, 0x01, req);
2663 //  return GE_NONE;
2664  
2665   GSM_Error error;
2666
2667   unsigned char req[]={0x00,0x01,0x7c,0x03};
2668     
2669   /* Checking */
2670   error=N6110_EnableExtendedCommands(0x01);
2671   if (error!=GE_NONE) return error;
2672
2673   return NULL_SendMessageSequence (20, &CurrentDialVoiceError, 4, 0x40, req);   
2674 }  
2675
2676 #ifndef UCLINUX
2677
2678 void N6110_ReplyEnterSecurityCode(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2679     
2680   switch(MessageBuffer[3]) {
2681
2682   case 0x0b:
2683 #ifdef DEBUG
2684     fprintf(stdout, _("Message: Security code accepted.\n"));
2685 #endif /* DEBUG */
2686     CurrentSecurityCodeError = GE_NONE;
2687     break;
2688
2689   default:
2690 #ifdef DEBUG
2691     fprintf(stdout, _("Message: Security code is wrong. You're not my big owner :-)\n"));
2692 #endif /* DEBUG */
2693     CurrentSecurityCodeError = GE_INVALIDSECURITYCODE;
2694   }
2695 }
2696
2697 GSM_Error N6110_EnterSecurityCode(GSM_SecurityCode SecurityCode)
2698 {
2699
2700   unsigned char req[15] = { N6110_FRAME_HEADER,
2701                             0x0a, /* Enter code request. */
2702                             0x00  /* Type of the entered code. */
2703                             };
2704   int i=0;
2705
2706   req[4]=SecurityCode.Type;
2707
2708   for (i=0; i<strlen(SecurityCode.Code);i++)
2709     req[5+i]=SecurityCode.Code[i];
2710
2711   req[5+strlen(SecurityCode.Code)]=0x00;
2712   req[6+strlen(SecurityCode.Code)]=0x00;
2713
2714   return NULL_SendMessageSequence
2715     (20, &CurrentSecurityCodeError, 7+strlen(SecurityCode.Code), 0x08, req);
2716 }
2717
2718 void N6110_ReplyGetSecurityCodeStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2719     
2720   *CurrentSecurityCodeStatus = MessageBuffer[4];
2721
2722 #ifdef DEBUG
2723   fprintf(stdout, _("Message: Security Code status received: "));
2724
2725   switch(*CurrentSecurityCodeStatus) {
2726
2727     case GSCT_SecurityCode: fprintf(stdout, _("waiting for Security Code.\n")); break;
2728     case GSCT_Pin         : fprintf(stdout, _("waiting for PIN.\n")); break;
2729     case GSCT_Pin2        : fprintf(stdout, _("waiting for PIN2.\n")); break;
2730     case GSCT_Puk         : fprintf(stdout, _("waiting for PUK.\n")); break;
2731     case GSCT_Puk2        : fprintf(stdout, _("waiting for PUK2.\n")); break;
2732     case GSCT_None        : fprintf(stdout, _("nothing to enter.\n")); break;
2733     default               : fprintf(stdout, _("Unknown!\n"));
2734   }
2735       
2736 #endif /* DEBUG */
2737
2738   CurrentSecurityCodeError = GE_NONE;
2739 }
2740
2741 GSM_Error N6110_GetSecurityCodeStatus(int *Status)
2742 {
2743
2744   unsigned char req[4] = { N6110_FRAME_HEADER,
2745                            0x07
2746                          };
2747
2748   CurrentSecurityCodeStatus=Status;
2749
2750   return NULL_SendMessageSequence
2751     (20, &CurrentSecurityCodeError, 4, 0x08, req);
2752 }
2753
2754 void N6110_ReplyGetSecurityCode(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2755
2756   int i;
2757   
2758 #ifdef DEBUG
2759   fprintf(stdout, _("Message: Security code received: "));
2760   switch (MessageBuffer[3]) {
2761     case GSCT_SecurityCode: fprintf(stdout, _("Security code"));break;
2762     case GSCT_Pin:  fprintf(stdout, _("PIN"));break;
2763     case GSCT_Pin2: fprintf(stdout, _("PIN2"));break;
2764     case GSCT_Puk:  fprintf(stdout, _("PUK"));break;
2765     case GSCT_Puk2: fprintf(stdout, _("PUK2"));break;
2766     default: fprintf(stdout, _("unknown !"));break;
2767   }
2768   if (MessageBuffer[4]==1) {
2769     fprintf(stdout, _(" allowed, value \""));
2770     if (MessageBuffer[3]==GSCT_SecurityCode) {
2771       for (i=0;i<5;i++) {fprintf(stdout, _("%c"), MessageBuffer[5+i]);}
2772     }
2773     if (MessageBuffer[3]==GSCT_Pin || MessageBuffer[3]==GSCT_Pin2 ||
2774         MessageBuffer[3]==GSCT_Puk || MessageBuffer[3]==GSCT_Puk2) {
2775       for (i=0;i<4;i++) {fprintf(stdout, _("%c"), MessageBuffer[5+i]);}
2776     }
2777     fprintf(stdout, _("\""));
2778   } else {
2779     fprintf(stdout, _(" not allowed"));  
2780   }
2781   fprintf(stdout, _("\n"));  
2782 #endif /* DEBUG */
2783       
2784   if (CurrentSecurityCode->Type==MessageBuffer[3] /* We wanted this code */
2785           && MessageBuffer[4]==1) {                      /* It's allowed */
2786     if (MessageBuffer[3]==GSCT_SecurityCode) {
2787       for (i=0;i<5;i++) {CurrentSecurityCode->Code[i]=MessageBuffer[5+i];}
2788       CurrentSecurityCode->Code[5]=0;
2789     }
2790     if (MessageBuffer[3]==GSCT_Pin || MessageBuffer[3]==GSCT_Pin2 ||
2791         MessageBuffer[3]==GSCT_Puk || MessageBuffer[3]==GSCT_Puk2) {
2792       for (i=0;i<4;i++) {CurrentSecurityCode->Code[i]=MessageBuffer[5+i];}
2793       CurrentSecurityCode->Code[4]=0;
2794     }
2795     CurrentSecurityCodeError=GE_NONE;
2796   } else
2797     CurrentSecurityCodeError=GE_INVALIDSECURITYCODE;
2798 }
2799
2800 GSM_Error N6110_GetSecurityCode(GSM_SecurityCode *SecurityCode)
2801 {
2802
2803   unsigned char req[4] = { 0x00,
2804                            0x01,0x6e, /* Get code request. */
2805                            0x00 };    /* Type of the requested code. */
2806
2807   GSM_Error error;
2808   
2809   error=N6110_EnableExtendedCommands(0x01);
2810   if (error!=GE_NONE) return error;
2811   
2812   req[3]=SecurityCode->Type;
2813
2814   CurrentSecurityCode=SecurityCode;
2815
2816   return NULL_SendMessageSequence
2817     (20, &CurrentSecurityCodeError, 4, 0x40, req);
2818 }
2819
2820 void N6110_ReplyPlayTone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2821
2822 #ifdef DEBUG
2823   fprintf(stdout, _("Message: answer for PlayTone frame\n"));      
2824 #endif
2825       
2826   CurrentPlayToneError=GE_NONE;      
2827 }
2828
2829 GSM_Error N6110_PlayTone(int Herz, u8 Volume)
2830 {
2831   unsigned char req[6] = { 0x00,0x01,0x8f,
2832                            0x00,   /* Volume */
2833                            0x00,   /* HerzLo */
2834                            0x00 }; /* HerzHi */
2835
2836   GSM_Error error;
2837
2838   /* PlayTone wasn't used earlier */
2839   if (CurrentPlayToneError==GE_UNKNOWN) {
2840     if (CurrentConnectionType!=GCT_MBUS)
2841       CurrentDisableKeepAlive=true;
2842
2843     error=N6110_EnableExtendedCommands(0x01);
2844     if (error!=GE_NONE) return error;
2845   }
2846
2847   /* For Herz==255*255 we have silent */  
2848   if (Herz!=255*255) {
2849     req[3]=Volume;
2850
2851     req[5]=Herz%256;
2852     req[4]=Herz/256;
2853   } else {
2854     req[3]=0;
2855
2856     req[5]=0;
2857     req[4]=0;
2858   }
2859
2860 #ifdef WIN32
2861   /* For Herz==255*255 we have silent and additionaly
2862      we wait for phone answer - it's important for MBUS */
2863   if (Herz==255*255) {
2864     error=NULL_SendMessageSequence
2865       (20, &CurrentPlayToneError, 6, 0x40, req);
2866
2867     CurrentPlayToneError=GE_UNKNOWN;
2868     CurrentDisableKeepAlive=false;
2869
2870     if (error!=GE_NONE) return error;
2871   } else {
2872     Protocol->SendMessage(6,0x40,req);
2873   }
2874 #else
2875   error=NULL_SendMessageSequence
2876     (20, &CurrentPlayToneError, 6, 0x40, req);
2877
2878   /* For Herz==255*255 we wait for phone answer - it's important for MBUS */
2879   if (Herz==255*255) {
2880     CurrentPlayToneError=GE_UNKNOWN;
2881     CurrentDisableKeepAlive=false;
2882   }
2883   
2884   if (error!=GE_NONE) return error;
2885
2886 #endif
2887     
2888   return(GE_NONE);
2889 }
2890
2891 void N6110_ReplyGetDateTime(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2892
2893   if (MessageBuffer[4]==0x01) {
2894     DecodeDateTime(MessageBuffer+8, CurrentDateTime);
2895
2896 #ifdef DEBUG
2897     fprintf(stdout, _("Message: Date and time\n"));
2898     fprintf(stdout, _("   Time: %02d:%02d:%02d\n"), CurrentDateTime->Hour, CurrentDateTime->Minute, CurrentDateTime->Second);
2899     fprintf(stdout, _("   Date: %4d/%02d/%02d\n"), CurrentDateTime->Year, CurrentDateTime->Month, CurrentDateTime->Day);
2900 #endif /* DEBUG */
2901
2902     CurrentDateTime->IsSet=true;
2903   } else {
2904
2905 #ifdef DEBUG
2906     fprintf(stdout, _("Message: Date and time not set in phone\n"));
2907 #endif
2908
2909     CurrentDateTime->IsSet=false;
2910   }
2911       
2912   CurrentDateTimeError=GE_NONE;
2913 }
2914
2915 GSM_Error N6110_GetDateTime(GSM_DateTime *date_time)
2916 {
2917   return N6110_PrivGetDateTime(date_time,0x11);
2918 }
2919
2920 GSM_Error N6110_PrivGetDateTime(GSM_DateTime *date_time, int msgtype)
2921 {
2922   unsigned char req[] = {N6110_FRAME_HEADER, 0x62};
2923
2924   CurrentDateTime=date_time;
2925
2926   return NULL_SendMessageSequence
2927     (50, &CurrentDateTimeError, 4, msgtype, req);
2928 }
2929
2930 void N6110_ReplyGetAlarm(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2931
2932 #ifdef DEBUG
2933   fprintf(stdout, _("Message: Alarm\n"));
2934   fprintf(stdout, _("   Alarm: %02d:%02d\n"), MessageBuffer[9], MessageBuffer[10]);
2935   fprintf(stdout, _("   Alarm is %s\n"), (MessageBuffer[8]==2) ? _("on"):_("off"));
2936 #endif /* DEBUG */
2937
2938   CurrentAlarm->Hour=MessageBuffer[9];
2939   CurrentAlarm->Minute=MessageBuffer[10];
2940   CurrentAlarm->Second=0;
2941
2942   CurrentAlarm->IsSet=(MessageBuffer[8]==2);
2943
2944   CurrentAlarmError=GE_NONE;
2945 }
2946
2947 GSM_Error N6110_GetAlarm(int alarm_number, GSM_DateTime *date_time)
2948 {
2949   return N6110_PrivGetAlarm(alarm_number,date_time,0x11);
2950 }
2951
2952 GSM_Error N6110_PrivGetAlarm(int alarm_number, GSM_DateTime *date_time, int msgtype)
2953 {
2954   unsigned char req[] = {N6110_FRAME_HEADER, 0x6d};
2955
2956   CurrentAlarm=date_time;
2957
2958   return NULL_SendMessageSequence
2959     (50, &CurrentAlarmError, 4, msgtype, req);
2960 }
2961
2962 void N6110_ReplyGetSMSCenter(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2963   
2964   switch (MessageBuffer[3]) {
2965
2966   case 0x34:
2967
2968     CurrentMessageCenter->No=MessageBuffer[4];
2969     CurrentMessageCenter->Format=MessageBuffer[6];
2970     CurrentMessageCenter->Validity=MessageBuffer[8];
2971     sprintf(CurrentMessageCenter->Name, "%s", MessageBuffer+33);
2972
2973     sprintf(CurrentMessageCenter->DefaultRecipient, "%s", GSM_UnpackSemiOctetNumber(MessageBuffer+9,false));
2974
2975     sprintf(CurrentMessageCenter->Number, "%s", GSM_UnpackSemiOctetNumber(MessageBuffer+21,false));
2976       
2977 #ifdef DEBUG
2978     fprintf(stdout, _("Message: SMS Center received:\n"));
2979     fprintf(stdout, _("   %d. SMS Center name is %s\n"), CurrentMessageCenter->No, CurrentMessageCenter->Name);
2980     fprintf(stdout, _("   SMS Center number is %s\n"), CurrentMessageCenter->Number);
2981     fprintf(stdout, _("   Default recipient number is %s\n"), CurrentMessageCenter->DefaultRecipient);
2982       
2983     fprintf(stdout, _("   SMS Center message format is "));
2984
2985     switch (CurrentMessageCenter->Format) {
2986
2987       case GSMF_Text  : fprintf(stdout, _("Text"));   break;
2988       case GSMF_Paging: fprintf(stdout, _("Paging")); break;
2989       case GSMF_Fax   : fprintf(stdout, _("Fax"));    break;
2990       case GSMF_Email : fprintf(stdout, _("Email"));  break;
2991       default         : fprintf(stdout, _("Unknown"));
2992     }
2993
2994     fprintf(stdout, "\n");
2995
2996     fprintf(stdout, _("   SMS Center message validity is "));
2997
2998     switch (CurrentMessageCenter->Validity) {
2999
3000       case GSMV_1_Hour  : fprintf(stdout, _("1 hour"));      break;
3001       case GSMV_6_Hours : fprintf(stdout, _("6 hours"));     break;
3002       case GSMV_24_Hours: fprintf(stdout, _("24 hours"));    break;
3003       case GSMV_72_Hours: fprintf(stdout, _("72 hours"));    break;
3004       case GSMV_1_Week  : fprintf(stdout, _("1 week"));      break;
3005       case GSMV_Max_Time: fprintf(stdout, _("Maximum time"));break;
3006       default           : fprintf(stdout, _("Unknown"));
3007     }
3008
3009     fprintf(stdout, "\n");
3010
3011 #endif /* DEBUG */
3012
3013     CurrentMessageCenterError=GE_NONE;
3014
3015     break;
3016
3017   case 0x35:
3018
3019     /* Number of entries depends on SIM card */
3020
3021 #ifdef DEBUG
3022     fprintf(stdout, _("Message: SMS Center error received:\n"));
3023     fprintf(stdout, _("   The request for SMS Center failed.\n"));
3024 #endif /* DEBUG */
3025
3026     /* FIXME: appropriate error. */
3027     CurrentMessageCenterError=GE_INTERNALERROR;
3028
3029     break;  
3030
3031   }
3032 }
3033
3034 /* This function sends to the mobile phone a request for the SMS Center */
3035 GSM_Error N6110_GetSMSCenter(GSM_MessageCenter *MessageCenter)
3036 {
3037   unsigned char req[] = { N6110_FRAME_HEADER, 0x33, 0x64,
3038                           0x00 /* SMS Center Number. */
3039                         };
3040
3041   req[5]=MessageCenter->No;
3042
3043   CurrentMessageCenter=MessageCenter;
3044
3045   return NULL_SendMessageSequence
3046     (50, &CurrentMessageCenterError, 6, 0x02, req);
3047 }
3048
3049 void N6110_ReplySetSMSCenter(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3050
3051 #ifdef DEBUG
3052   fprintf(stdout, _("Message: SMS Center correctly set.\n"));
3053 #endif
3054   CurrentMessageCenterError=GE_NONE;
3055 }
3056
3057 /* This function set the SMS Center profile on the phone. */
3058 GSM_Error N6110_SetSMSCenter(GSM_MessageCenter *MessageCenter)
3059 {
3060   unsigned char req[64] = { N6110_FRAME_HEADER, 0x30, 0x64,
3061                             0x00, /* SMS Center Number. */
3062                             0x00, /* Unknown. */
3063                             0x00, /* SMS Message Format. */
3064                             0x00, /* Unknown. */
3065                             0x00, /* Validity. */
3066                             0,0,0,0,0,0,0,0,0,0,0,0, /* Default recipient number */
3067                             0,0,0,0,0,0,0,0,0,0,0,0 /* Message Center Number. */
3068                             /* Message Center Name. */
3069                           };
3070
3071   req[5]=MessageCenter->No;
3072   req[7]=MessageCenter->Format;
3073   req[9]=MessageCenter->Validity;
3074
3075   req[10]=GSM_PackSemiOctetNumber(MessageCenter->DefaultRecipient, req+11, false);
3076
3077   req[22]=GSM_PackSemiOctetNumber(MessageCenter->Number, req+23, false);
3078
3079   sprintf(req+34, "%s", MessageCenter->Name);
3080
3081   CurrentMessageCenter=MessageCenter;
3082
3083   return NULL_SendMessageSequence
3084     (50, &CurrentMessageCenterError, 35+strlen(MessageCenter->Name), 0x02, req);
3085 }
3086
3087 void N6110_ReplyGetSMSStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3088
3089   switch (MessageBuffer[3]) {
3090
3091   case 0x37:
3092
3093 #ifdef DEBUG
3094     fprintf(stdout, _("Message: SMS Status Received\n"));
3095     fprintf(stdout, _("   The number of messages: %d\n"), MessageBuffer[10]);
3096     fprintf(stdout, _("   Unread messages: %d\n"), MessageBuffer[11]);
3097 #endif /* DEBUG */
3098
3099     CurrentSMSStatus->UnRead = MessageBuffer[11];
3100     CurrentSMSStatus->Number = MessageBuffer[10];
3101     
3102     CurrentSMSStatusError = GE_NONE;
3103     break;
3104
3105   case 0x38:
3106
3107 #ifdef DEBUG
3108     fprintf(stdout, _("Message: SMS Status error, probably not authorized by PIN\n"));
3109 #endif /* DEBUG */
3110
3111     CurrentSMSStatusError = GE_INTERNALERROR;
3112     break;
3113           
3114   }
3115 }
3116
3117 GSM_Error N6110_GetSMSStatus(GSM_SMSStatus *Status)
3118 {
3119   unsigned char req[] = {N6110_FRAME_HEADER, 0x36, 0x64};
3120
3121   CurrentSMSStatus = Status;
3122
3123   return NULL_SendMessageSequence
3124     (10, &CurrentSMSStatusError, 5, 0x14, req);
3125 }
3126
3127 GSM_Error N6110_GetSMSFolders ( GSM_SMSFolders *folders)
3128 {
3129   folders->number=2;
3130
3131   strcpy(folders->Folder[0].Name,"Inbox");
3132   strcpy(folders->Folder[1].Name,"Outbox");
3133   
3134   return GE_NONE;
3135 }
3136
3137 #endif /* UCLINUX */
3138
3139 GSM_Error N6110_GetIMEI(char *imei)
3140 {
3141   if (strlen(Current_IMEI)>0) {
3142     strncpy (imei, Current_IMEI, GSM_MAX_IMEI_LENGTH);
3143     return (GE_NONE);
3144   }
3145   else
3146     return (GE_TRYAGAIN);
3147 }
3148
3149 GSM_Error N6110_GetRevision(char *revision)
3150 {
3151
3152   if (strlen(Current_Revision)>0) {
3153     strncpy (revision, Current_Revision, GSM_MAX_REVISION_LENGTH);
3154     return (GE_NONE);
3155   }
3156   else
3157     return (GE_TRYAGAIN);
3158 }
3159
3160 static GSM_Error N6110_GetModel(char *model)
3161 {
3162   if (strlen(Current_Model)>0) {
3163     strncpy (model, Current_Model, GSM_MAX_MODEL_LENGTH);
3164     return (GE_NONE);
3165   }
3166   else
3167     return (GE_TRYAGAIN);
3168 }
3169
3170 #ifndef UCLINUX
3171
3172 void N6110_ReplySetDateTime(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3173
3174   switch (MessageBuffer[4]) {
3175
3176     case 0x01:
3177 #ifdef DEBUG
3178       fprintf(stdout, _("Message: Date and time set correctly\n"));
3179 #endif /* DEBUG */
3180       CurrentSetDateTimeError=GE_NONE;
3181       break;
3182       
3183     default:
3184 #ifdef DEBUG
3185       fprintf(stdout, _("Message: Date and time setting error\n"));
3186 #endif /* DEBUG */
3187       CurrentSetDateTimeError=GE_INVALIDDATETIME;
3188
3189   }
3190 }
3191
3192 /* Needs SIM card with PIN in phone */
3193 GSM_Error N6110_SetDateTime(GSM_DateTime *date_time)
3194 {
3195   return N6110_PrivSetDateTime(date_time,0x11);
3196 }
3197
3198 /* Needs SIM card with PIN in phone */
3199 GSM_Error N6110_PrivSetDateTime(GSM_DateTime *date_time, int msgtype)
3200 {
3201
3202   unsigned char req[] = { N6110_FRAME_HEADER,
3203                           0x60, /* set-time subtype */
3204                           0x01, 0x01, 0x07, /* unknown */
3205                           0x00, 0x00, /* Year (0x07cf = 1999) */
3206                           0x00, 0x00, /* Month Day */
3207                           0x00, 0x00, /* Hours Minutes */
3208                           0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
3209                         };
3210
3211   EncodeDateTime(req+7, date_time);
3212
3213   return NULL_SendMessageSequence
3214     (20, &CurrentSetDateTimeError, 14, msgtype, req);
3215 }
3216
3217 void N6110_ReplySetAlarm(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3218
3219   switch (MessageBuffer[4]) {
3220
3221     case 0x01:
3222 #ifdef DEBUG
3223       fprintf(stdout, _("Message: Alarm set correctly\n"));
3224 #endif /* DEBUG */
3225       CurrentSetAlarmError=GE_NONE;
3226       break;
3227       
3228     default:
3229 #ifdef DEBUG
3230       fprintf(stdout, _("Message: Alarm setting error\n"));
3231 #endif /* DEBUG */
3232       CurrentSetAlarmError=GE_INVALIDDATETIME;
3233
3234   }
3235 }
3236
3237 /* FIXME: we should also allow to set the alarm off :-) */
3238 GSM_Error N6110_SetAlarm(int alarm_number, GSM_DateTime *date_time)
3239 {
3240   return N6110_PrivSetAlarm(alarm_number,date_time, 0x11);
3241 }
3242
3243 /* FIXME: we should also allow to set the alarm off :-) */
3244 GSM_Error N6110_PrivSetAlarm(int alarm_number, GSM_DateTime *date_time, int msgtype)
3245 {
3246
3247   unsigned char req[] = { N6110_FRAME_HEADER,
3248                           0x6b, /* set-alarm subtype */
3249                           0x01, 0x20, 0x03, /* unknown */
3250                           0x02,       /* should be alarm on/off, but it don't works */
3251                           0x00, 0x00, /* Hours Minutes */
3252                           0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
3253                         };
3254
3255   req[8] = date_time->Hour;
3256   req[9] = date_time->Minute;
3257
3258   return NULL_SendMessageSequence
3259     (50, &CurrentSetAlarmError, 11, msgtype, req);
3260 }
3261
3262 #endif /* UCLINUX */
3263
3264 static void N6110_ReplyGetMemoryLocation(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3265
3266   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
3267   char model[64];
3268
3269   int i, tmp, count;
3270     
3271   switch (MessageBuffer[3]) {
3272
3273   case 0x02:
3274
3275     CurrentPhonebookEntry->Empty = true;
3276
3277     count=MessageBuffer[5];
3278           
3279 #ifdef DEBUG
3280     fprintf(stdout, _("Message: Phonebook entry received:\n"));
3281     fprintf(stdout, _("   Name: "));
3282
3283     for (tmp=0; tmp <count; tmp++)
3284     {
3285       if (MessageBuffer[6+tmp]==1) fprintf(stdout, "%c", '~'); else //enables/disables blinking
3286       if (MessageBuffer[6+tmp]==0) fprintf(stdout, "%c", '`'); else //hides rest ot contents
3287       fprintf(stdout, "%c", MessageBuffer[6+tmp]);
3288     }
3289
3290     fprintf(stdout, "\n");
3291 #endif /* DEBUG */
3292
3293     while (N6110_GetModel(model)  != GE_NONE)
3294       sleep(1);
3295         
3296     if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {//pbk with Unicode
3297 #ifndef UCLINUX
3298       DecodeUnicode (CurrentPhonebookEntry->Name, MessageBuffer+6, count/2);
3299       CurrentPhonebookEntry->Name[count/2] = 0x00;
3300 #else /* UCLINUX */
3301       fprintf(stderr,"FATAL ERROR: DecodeUnicode disabled!\n");
3302       exit(1);
3303 #endif /* UCLINUX */
3304     } else {
3305       memcpy(CurrentPhonebookEntry->Name, MessageBuffer + 6, count);
3306       CurrentPhonebookEntry->Name[count] = 0x00;
3307     }
3308
3309     CurrentPhonebookEntry->Empty = false;
3310
3311     for (tmp=0; tmp <count; tmp++)
3312     {
3313       if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {//pbk with Unicode
3314         /* We check only 1'st, 3'rd, ... char */
3315         if (tmp%2!=0 && MessageBuffer[6+tmp]==1) CurrentPhonebookEntry->Name[tmp/2]='~'; //enables/disables blinking
3316         if (tmp%2!=0 && MessageBuffer[6+tmp]==0) CurrentPhonebookEntry->Name[tmp/2]='`'; //hides rest ot contents
3317       } else {
3318         if (MessageBuffer[6+tmp]==1) CurrentPhonebookEntry->Name[tmp]='~'; //enables/disables blinking
3319         if (MessageBuffer[6+tmp]==0) CurrentPhonebookEntry->Name[tmp]='`'; //hides rest ot contents
3320       }
3321     }
3322
3323     i=7+count;
3324     count=MessageBuffer[6+count];
3325
3326 #ifdef DEBUG
3327     fprintf(stdout, _("   Number: "));
3328
3329     for (tmp=0; tmp <count; tmp++)
3330       fprintf(stdout, "%c", MessageBuffer[i+tmp]);
3331
3332     fprintf(stdout, "\n");
3333 #endif /* DEBUG */
3334
3335     memcpy(CurrentPhonebookEntry->Number, MessageBuffer + i, count);
3336     CurrentPhonebookEntry->Number[count] = 0x00;
3337     CurrentPhonebookEntry->Group = MessageBuffer[i+count];
3338       
3339     /* Phone doesn't have entended phonebook */
3340     CurrentPhonebookEntry->SubEntriesCount = 0;
3341
3342     /* But for these memories data is saved and we can save it using 7110/6210 style */
3343     if (CurrentPhonebookEntry->MemoryType==GMT_DC ||
3344         CurrentPhonebookEntry->MemoryType==GMT_RC ||
3345         CurrentPhonebookEntry->MemoryType==GMT_MC) {
3346         CurrentPhonebookEntry->SubEntriesCount = 1;
3347         CurrentPhonebookEntry->SubEntries[0].EntryType=N7110_ENTRYTYPE_DATE;
3348         CurrentPhonebookEntry->SubEntries[0].NumberType=0;
3349         CurrentPhonebookEntry->SubEntries[0].BlockNumber=1;
3350         DecodeDateTime(MessageBuffer+(i+count+2),&CurrentPhonebookEntry->SubEntries[0].data.Date);
3351
3352 #ifdef DEBUG
3353       fprintf(stdout, _("   Date: "));
3354       fprintf(stdout, "%02u.%02u.%04u\n",
3355           CurrentPhonebookEntry->SubEntries[0].data.Date.Day,
3356           CurrentPhonebookEntry->SubEntries[0].data.Date.Month,
3357           CurrentPhonebookEntry->SubEntries[0].data.Date.Year);
3358       fprintf(stdout, _("   Time: "));
3359       fprintf(stdout, "%02u:%02u:%02u\n",
3360           CurrentPhonebookEntry->SubEntries[0].data.Date.Hour,
3361           CurrentPhonebookEntry->SubEntries[0].data.Date.Minute,
3362           CurrentPhonebookEntry->SubEntries[0].data.Date.Second);
3363 #endif /* DEBUG */
3364
3365       /* These values are set, when date and time unavailable in phone.
3366          Values from 3310 - in other can be different */
3367       if (CurrentPhonebookEntry->SubEntries[0].data.Date.Day==20 &&
3368           CurrentPhonebookEntry->SubEntries[0].data.Date.Month==1 &&
3369           CurrentPhonebookEntry->SubEntries[0].data.Date.Year==2118 &&
3370           CurrentPhonebookEntry->SubEntries[0].data.Date.Hour==3 &&
3371           CurrentPhonebookEntry->SubEntries[0].data.Date.Minute==14 &&
3372           CurrentPhonebookEntry->SubEntries[0].data.Date.Second==7)
3373           CurrentPhonebookEntry->SubEntriesCount = 0;
3374     }
3375
3376     /* Signal no error to calling code. */
3377     CurrentPhonebookError = GE_NONE;
3378
3379     break;
3380
3381   case 0x03:
3382
3383 #ifdef DEBUG
3384     fprintf(stdout, _("Message: Phonebook read entry error received:\n"));
3385 #endif /* DEBUG */
3386
3387     switch (MessageBuffer[4]) {
3388
3389       case 0x7d:
3390 #ifdef DEBUG
3391         fprintf(stdout, _("   Invalid memory type!\n"));
3392 #endif /* DEBUG */
3393         CurrentPhonebookError = GE_INVALIDMEMORYTYPE;
3394         break;
3395
3396       default:
3397 #ifdef DEBUG
3398         fprintf(stdout, _("   Unknown error!\n"));
3399 #endif /* DEBUG */
3400         CurrentPhonebookError = GE_INTERNALERROR;
3401     }
3402
3403     break;
3404
3405   }
3406 }
3407
3408 /* Routine to get specifed phone book location.  Designed to be called by
3409    application.  Will block until location is retrieved or a timeout/error
3410    occurs. */
3411 GSM_Error N6110_GetMemoryLocation(GSM_PhonebookEntry *entry)
3412 {
3413   unsigned char req[] = {N6110_FRAME_HEADER, 0x01, 0x00, 0x00, 0x00};
3414
3415   CurrentPhonebookEntry = entry;
3416
3417   req[4] = N6110_GetMemoryType(entry->MemoryType);
3418   req[5] = entry->Location;
3419
3420   return NULL_SendMessageSequence
3421     (50, &CurrentPhonebookError, 7, 0x03, req);
3422 }
3423
3424 static void N6110_ReplyWritePhonebookLocation(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3425
3426   switch (MessageBuffer[3]) {
3427
3428   case 0x05:
3429
3430 #ifdef DEBUG
3431     fprintf(stdout, _("Message: Phonebook written correctly.\n"));
3432 #endif /* DEBUG */
3433     CurrentPhonebookError = GE_NONE;
3434     break;
3435
3436   case 0x06:
3437
3438     switch (MessageBuffer[4]) {
3439       /* FIXME: other errors? When I send the phonebook with index of 350 it
3440          still report error 0x7d :-( */
3441       case 0x7d:
3442 #ifdef DEBUG
3443         fprintf(stdout, _("Message: Phonebook not written - name is too long.\n"));
3444 #endif /* DEBUG */
3445         CurrentPhonebookError = GE_PHBOOKNAMETOOLONG;
3446         break;
3447
3448       default:
3449 #ifdef DEBUG
3450         fprintf(stdout, _("   Unknown error!\n"));
3451 #endif /* DEBUG */
3452         CurrentPhonebookError = GE_INTERNALERROR;
3453     }
3454   }
3455 }
3456
3457 /* Routine to write phonebook location in phone. Designed to be called by
3458    application code. Will block until location is written or timeout
3459    occurs. */
3460 GSM_Error N6110_WritePhonebookLocation(GSM_PhonebookEntry *entry)
3461 {
3462   unsigned char req[128] = { N6110_FRAME_HEADER, 0x04, 0x00, 0x00 };
3463   int i=0, current=0;
3464
3465   req[4] = N6110_GetMemoryType(entry->MemoryType);
3466   req[5] = entry->Location;
3467
3468   current=7;
3469
3470   if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {
3471 #ifndef UCLINUX
3472
3473      req[6] = strlen(entry->Name)*2;
3474
3475      EncodeUnicode (req+current,entry->Name ,strlen(entry->Name));
3476      
3477      for (i=0; i<strlen(entry->Name); i++)
3478      {
3479        /* here we encode "special" chars */
3480        if (entry->Name[i]=='~') req[current+i*2]=1; //enables/disables blinking
3481        if (entry->Name[i]=='`') req[current+i*2]=0; //hides rest ot contents
3482      }
3483
3484      current+=strlen(entry->Name)*2;
3485
3486 #else /* UCLINUX */
3487
3488      fprintf(stderr,"FATAL ERROR: EncodeUnicode disabled!\n");
3489      exit(1);
3490
3491 #endif /* UCLINUX */
3492   } else {
3493
3494     req[6] = strlen(entry->Name);
3495
3496     for (i=0; i<strlen(entry->Name); i++)
3497     {
3498       req[current+i] = entry->Name[i];
3499
3500       /* here we encode "special" chars */
3501       if (entry->Name[i]=='~') req[current+i]=1; //enables/disables blinking
3502       if (entry->Name[i]=='`') req[current+i]=0; //hides rest ot contents
3503     }
3504
3505     current+=strlen(entry->Name);
3506   }
3507
3508   req[current++]=strlen(entry->Number);
3509
3510   for (i=0; i<strlen(entry->Number); i++)
3511     req[current+i] = entry->Number[i];
3512
3513   current+=strlen(entry->Number);
3514
3515   /* Jano: This allow to save 14 characters name into SIM memory, when
3516      No Group is selected. */
3517   if (entry->Group == 5)
3518     req[current++]=0xff;
3519   else
3520     req[current++]=entry->Group;
3521
3522   return NULL_SendMessageSequence
3523     (50, &CurrentPhonebookError, current, 0x03, req);
3524 }
3525
3526 #ifndef UCLINUX
3527
3528 void N6110_ReplyNetmonitor(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3529
3530   switch(MessageBuffer[3]) {
3531
3532     case 0x00:
3533 #ifdef DEBUG
3534       fprintf(stdout, _("Message: Netmonitor correctly set.\n"));
3535 #endif /* DEBUG */
3536       CurrentNetmonitorError=GE_NONE;  
3537       break;
3538       
3539     default:
3540 #ifdef DEBUG
3541       fprintf(stdout, _("Message: Netmonitor menu %d received:\n"), MessageBuffer[3]);
3542       fprintf(stdout, "%s\n", MessageBuffer+4);
3543 #endif /* DEBUG */
3544
3545       strcpy(CurrentNetmonitor, MessageBuffer+4);
3546
3547       CurrentNetmonitorError=GE_NONE;  
3548   }
3549 }
3550
3551 GSM_Error N6110_NetMonitor(unsigned char mode, char *Screen)
3552 {
3553   unsigned char req[] = { 0x00, 0x01, 0x7e, 0x00 };
3554   
3555   GSM_Error error;
3556   
3557   error=N6110_EnableExtendedCommands(0x01);
3558   if (error!=GE_NONE) return error;
3559
3560   CurrentNetmonitor=Screen;
3561
3562   req[3]=mode;
3563
3564   return NULL_SendMessageSequence
3565     (20, &CurrentNetmonitorError, 4, 0x40, req);
3566 }
3567
3568 /* Doesn't work in N3210. */
3569 /* In other allow to access phone menu without SIM card (just send any sequence) */
3570 GSM_Error N6110_SendDTMF(char *String)
3571 {
3572   unsigned char req[64] = { N6110_FRAME_HEADER, 0x50,
3573                             0x00 /* Length of DTMF string. */
3574                           };
3575                           
3576   u8 length=strlen(String);
3577
3578   if (length>59) length=59;
3579   
3580   req[4] = length;
3581   
3582   memcpy(req+5,String,length);
3583
3584   return NULL_SendMessageSequence
3585     (20, &CurrentSendDTMFError, 5+length, 0x01, req);
3586 }
3587
3588 #endif /* UCLINUX */
3589
3590 static void N6110_ReplyGetSpeedDial(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3591
3592   switch (MessageBuffer[3]) {
3593
3594   case 0x17:
3595
3596     switch (MessageBuffer[4]) {
3597       case 0x02: CurrentSpeedDialEntry->MemoryType = GMT_ME;
3598       default  : CurrentSpeedDialEntry->MemoryType = GMT_SM;
3599     }
3600       
3601     CurrentSpeedDialEntry->Location = MessageBuffer[5];
3602
3603 #ifdef DEBUG
3604     fprintf(stdout, _("Message: Speed dial entry received:\n"));
3605     fprintf(stdout, _("   Location: %d\n"), CurrentSpeedDialEntry->Location);
3606     fprintf(stdout, _("   MemoryType: %s\n"), N6110_MemoryType_String[CurrentSpeedDialEntry->MemoryType]);
3607     fprintf(stdout, _("   Number: %d\n"), CurrentSpeedDialEntry->Number);
3608 #endif /* DEBUG */
3609
3610     CurrentSpeedDialError=GE_NONE;
3611     break;
3612
3613   case 0x18:
3614
3615 #ifdef DEBUG
3616     fprintf(stdout, _("Message: Speed dial entry error\n"));
3617 #endif /* DEBUG */
3618     CurrentSpeedDialError=GE_INVALIDSPEEDDIALLOCATION;
3619     break;
3620
3621   }
3622 }
3623
3624 GSM_Error N6110_GetSpeedDial(GSM_SpeedDial *entry)
3625 {
3626
3627   unsigned char req[] = { N6110_FRAME_HEADER,
3628                           0x16,
3629                           0x00  /* The number of speed dial. */
3630                         };
3631
3632   CurrentSpeedDialEntry = entry;
3633
3634   req[4] = entry->Number;
3635
3636   return NULL_SendMessageSequence
3637     (20, &CurrentSpeedDialError, 5, 0x03, req);
3638 }
3639
3640 static void N6110_ReplySetSpeedDial(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3641
3642   switch (MessageBuffer[3]) {
3643
3644   case 0x1a:
3645
3646 #ifdef DEBUG
3647     fprintf(stdout, _("Message: Speed dial entry set.\n"));
3648 #endif /* DEBUG */
3649     CurrentSpeedDialError=GE_NONE;
3650     break;
3651
3652   case 0x1b:
3653
3654 #ifdef DEBUG
3655     fprintf(stdout, _("Message: Speed dial entry setting error.\n"));
3656 #endif /* DEBUG */
3657     CurrentSpeedDialError=GE_INVALIDSPEEDDIALLOCATION;
3658     break;
3659
3660   }
3661 }
3662
3663 GSM_Error N6110_SetSpeedDial(GSM_SpeedDial *entry)
3664 {
3665
3666   unsigned char req[] = { N6110_FRAME_HEADER,
3667                           0x19,
3668                           0x00, /* Number */
3669                           0x00, /* Memory Type */
3670                           0x00  /* Location */
3671                         };
3672
3673   req[4] = entry->Number;
3674
3675   switch (entry->MemoryType) {
3676     case GMT_ME: req[5] = 0x02;
3677     default    : req[5] = 0x03;
3678   }
3679
3680   req[6] = entry->Location;
3681
3682   return NULL_SendMessageSequence
3683     (20, &CurrentSpeedDialError, 7, 0x03, req);
3684 }
3685
3686 #ifndef UCLINUX
3687
3688 /* This function finds parts of SMS in frame used in new Nokia phones
3689    in internal protocols (they're coded according to GSM 03.40), copies them
3690    to GSM_ETSISMSMessage and calls GSM_DecodeETSISMS to decode
3691    GSM_ETSISMSMessage to GSM_SMSMessage structure */
3692 GSM_Error GSM_DecodeNokiaSMSFrame(GSM_SMSMessage *SMS, unsigned char *req, int length)
3693 {
3694   SMS_MessageType PDU=SMS_Deliver;
3695   GSM_ETSISMSMessage ETSI;
3696   int offset=0,i;
3697
3698   ETSI.firstbyte=req[12];
3699
3700   /* See GSM 03.40 section 9.2.3.1 */
3701   if ((ETSI.firstbyte & 0x03) == 0x01) PDU=SMS_Submit;
3702   if ((ETSI.firstbyte & 0x03) == 0x02) PDU=SMS_Status_Report;
3703
3704   switch (PDU) {
3705     case SMS_Submit       : offset=5;break;
3706     case SMS_Deliver      : offset=4;break;
3707     case SMS_Status_Report: offset=3;break;
3708     default:                break;
3709   }
3710
3711   for (i=0;i<req[0]+1;i++)
3712     ETSI.SMSCNumber[i]=req[i];
3713
3714   for (i=0;i<((req[12+offset]+1)/2+1)+1;i++)
3715     ETSI.Number[i]=req[i+12+offset];
3716
3717   switch (PDU) {
3718     case SMS_Submit:
3719       ETSI.TPDCS=req[10+offset];
3720       ETSI.TPUDL=req[11+offset];
3721       ETSI.TPVP=0;  //no support for now
3722       ETSI.TPPID=0; //no support for now
3723       for(i=31+offset;i<length;i++)
3724         ETSI.MessageText[i-31-offset]=req[i];
3725       break;
3726     case SMS_Deliver:
3727       ETSI.TPDCS=req[10+offset];
3728       ETSI.TPUDL=req[11+offset];
3729       ETSI.TPPID=0; //no support for now
3730       for(i=31+offset;i<length;i++)
3731         ETSI.MessageText[i-31-offset]=req[i];
3732       for(i=0;i<7;i++)
3733         ETSI.DeliveryDateTime[i]=req[i+24+offset];
3734       break;
3735     case SMS_Status_Report:
3736       for(i=0;i<7;i++)
3737         ETSI.DeliveryDateTime[i]=req[i+24+offset];
3738       ETSI.TPStatus=req[14];
3739       for(i=0;i<7;i++)
3740         ETSI.SMSCDateTime[i]=req[i+34];
3741       break;
3742     default:
3743       break;
3744   }
3745
3746   GSM_DecodeETSISMS(SMS, &ETSI);
3747
3748   SMS->Name[0]=0;
3749
3750   return GE_NONE;
3751 }
3752
3753 void N6110_ReplyGetSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3754
3755   int offset;
3756   
3757   switch (MessageBuffer[3]) {
3758
3759   case 0x08:
3760
3761     switch (MessageBuffer[7]) {
3762
3763       case 0x00:
3764         CurrentSMSMessage->Type = GST_SMS;
3765         CurrentSMSMessage->folder=GST_INBOX;
3766         offset=4;
3767         break;
3768
3769       case 0x01:
3770         CurrentSMSMessage->Type = GST_DR;
3771         CurrentSMSMessage->folder=GST_INBOX;
3772         offset=3;
3773         break;
3774
3775       case 0x02:
3776         CurrentSMSMessage->Type = GST_SMS;
3777         CurrentSMSMessage->folder=GST_OUTBOX;
3778         offset=5;
3779         break;
3780
3781       default:
3782         CurrentSMSMessage->Type = GST_UN;
3783         offset=4;
3784         break;
3785
3786     }
3787
3788     /* Field Short Message Status - MessageBuffer[4] seems not to be
3789        compliant with GSM 07.05 spec.
3790        Meaning     Nokia protocol       GMS spec
3791        ----------------------------------------------------
3792        MO Sent     0x05                 0x07 or 0x01
3793        MO Not sent 0x07                 0x06 or 0x00
3794        MT Read     0x01                 0x05 or 0x01
3795        MT Not read 0x03                 0x04 or 0x00
3796        ----------------------------------------------------
3797        See GSM 07.05 section 2.5.2.6 and correct me if I'm wrong.
3798        
3799                                          Pawel Kot */
3800
3801     if (MessageBuffer[4] & 0x02) CurrentSMSMessage->Status = GSS_NOTSENTREAD;
3802                             else CurrentSMSMessage->Status = GSS_SENTREAD;
3803
3804 #ifdef DEBUG
3805     fprintf(stdout, _("Number: %d\n"), MessageBuffer[6]);
3806
3807     if (CurrentSMSMessage->folder!=1) { //GST_OUTBOX
3808       fprintf(stdout, _("Message: Received SMS (mobile terminated)\n"));
3809     } else {
3810       fprintf(stdout, _("Message: Outbox message (mobile originated)\n"));
3811     }
3812
3813     if (CurrentSMSMessage->Type == GST_DR) fprintf(stdout, _("   Delivery Report\n"));
3814     if (CurrentSMSMessage->Type == GST_UN) fprintf(stdout, _("   Unknown type\n"));
3815
3816     if (CurrentSMSMessage->folder==1) { //GST_OUTBOX
3817       if (CurrentSMSMessage->Status) fprintf(stdout, _("   Sent\n"));
3818                                 else fprintf(stdout, _("   Not sent\n"));
3819     } else {
3820       if (CurrentSMSMessage->Status) fprintf(stdout, _("   Read\n"));
3821                                 else fprintf(stdout, _("   Not read\n"));
3822     }
3823 #endif
3824
3825     CurrentSMSPointer=GSM_DecodeNokiaSMSFrame(CurrentSMSMessage, MessageBuffer+8, MessageLength-8);
3826
3827     CurrentSMSMessage->MemoryType = MessageBuffer[5];
3828     CurrentSMSMessage->MessageNumber = MessageBuffer[6];
3829  
3830     /* Signal no error to calling code. */
3831     CurrentSMSMessageError = GE_NONE;
3832
3833 #ifdef DEBUG
3834     fprintf(stdout, "\n");
3835 #endif
3836
3837     break;
3838
3839   case 0x09:
3840
3841     /* We have requested invalid or empty location. */
3842
3843 #ifdef DEBUG
3844     fprintf(stdout, _("Message: SMS reading failed\n"));
3845
3846     switch (MessageBuffer[4]) {
3847       case 0x02:
3848         fprintf(stdout, _("   Invalid location!\n"));break;
3849       case 0x07:
3850         fprintf(stdout, _("   Empty SMS location.\n"));break;
3851       case 0x0c:
3852         fprintf(stdout, _("   No access to memory (no PIN on card ?)\n"));break;
3853       default:      
3854         fprintf(stdout, _("   Error code %i - please report it \n"),MessageBuffer[4]);break;
3855     }
3856 #endif /* DEBUG */
3857
3858     switch (MessageBuffer[4]) {
3859       case 0x02:CurrentSMSMessageError = GE_INVALIDSMSLOCATION;break;
3860       case 0x07:CurrentSMSMessageError = GE_EMPTYSMSLOCATION;break;
3861       case 0x0c:CurrentSMSMessageError = GE_NOACCESS;break;
3862       default  :CurrentSMSMessageError = GE_UNKNOWN;break;
3863     }
3864
3865     break;
3866
3867   }
3868 }
3869
3870 GSM_Error N6110_GetSMSMessage(GSM_SMSMessage *message)
3871 {
3872
3873   unsigned char req[] = { N6110_FRAME_HEADER,
3874                           0x07,
3875                           0x02, /* Unknown */
3876                           0x00, /* Location */
3877                           0x01, 0x64};