3fdd16af2d8cd6f9624f621a7901874faf07b100
[gnokii.git] / common / newmodules / n6110.c
1 /*
2
3   G N O K I I
4
5   A Linux/Unix toolset and driver for Nokia mobile phones.
6
7   Released under the terms of the GNU GPL, see file COPYING for more details.
8
9   This file provides an API for accessing functions on the 6110 and similar
10   phones.
11
12 */
13
14 #include "config.h"
15
16 /* "Turn on" prototypes in n-6110.h */
17
18 #define __n_6110_c 
19
20 /* System header files */
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25 #ifdef WIN32
26   #include "misc_win32.h"
27 #endif
28  
29 /* Various header file */
30 #ifndef VC6
31   #include "config.h"
32 #endif
33
34 #include "gsm-api.h"
35 #include "gsm-coding.h"
36 #include "newmodules/n6110.h"
37 #include "newmodules/n7110.h"
38 #include "protocol/fbus.h"
39 #include "devices/device.h"
40 /* Global variables used by code in gsm-api.c to expose the functions
41    supported by this model of phone. */
42
43
44 /* Here we initialise model specific functions. */
45 GSM_Functions N6110_Functions = {
46   N6110_Initialise,
47   N6110_DispatchMessage,
48   NULL_Terminate,
49   NULL_KeepAlive,
50   N6110_GetMemoryLocation,
51   N6110_WritePhonebookLocation,
52   N6110_GetSpeedDial,
53   N6110_SetSpeedDial,
54   N6110_GetMemoryStatus,
55 #ifndef UCLINUX
56   N6110_GetSMSStatus,
57   N6110_GetSMSCenter,
58   N6110_SetSMSCenter,
59   N6110_GetSMSMessage,
60   N6110_DeleteSMSMessage,
61   N6110_SendSMSMessage,
62   N6110_SaveSMSMessage,
63 #else /* UCLINUX */
64   NULL,
65   NULL,
66   NULL,
67   NULL,
68   NULL,
69   NULL,
70   NULL,
71 #endif /* UCLINUX */
72   N6110_GetRFLevel,
73   N6110_GetBatteryLevel,
74   N6110_GetPowerSource,
75 #ifndef UCLINUX
76   N6110_GetDisplayStatus,
77   N6110_EnterSecurityCode,
78   N6110_GetSecurityCodeStatus,
79   N6110_GetSecurityCode,
80 #else /* UCLINUX */
81   NULL,
82   NULL,
83   NULL,
84   NULL,
85 #endif /* UCLINUX */
86   N6110_GetIMEI,
87   N6110_GetRevision,
88   N6110_GetModel,
89 #ifndef UCLINUX
90   N6110_GetDateTime,
91   N6110_SetDateTime,
92   N6110_GetAlarm,
93   N6110_SetAlarm,
94   N6110_DialVoice,
95 #else /* UCLINUX */
96   NULL,
97   NULL,
98   NULL,
99   NULL,
100   NULL,
101 #endif /* UCLINUX */
102   N6110_DialData,
103 #ifndef UCLINUX
104   N6110_GetIncomingCallNr,
105   N6110_GetNetworkInfo,
106   N6110_GetCalendarNote,
107   N6110_WriteCalendarNote,
108   N6110_DeleteCalendarNote,
109   N6110_NetMonitor,
110   N6110_SendDTMF,
111   N6110_GetBitmap,
112   N6110_SetBitmap,
113   N6110_SetRingTone,
114   N6110_SetBinRingTone,
115   N6110_GetBinRingTone,
116 #else /* UCLINUX */
117   NULL,
118   NULL,
119   NULL,
120   NULL,
121   NULL,
122   NULL,
123   NULL,
124   NULL,
125   NULL,
126   NULL,
127   NULL,
128   NULL,
129 #endif /* UCLINUX */
130   N6110_Reset,
131 #ifndef UCLINUX
132   N6110_GetProfile,
133   N6110_SetProfile,
134 #else /* UCLINUX */
135   NULL,
136   NULL,
137 #endif /* UCLINUX */
138   N6110_SendRLPFrame,
139   N6110_CancelCall,
140 #ifndef UCLINUX
141   N6110_PressKey,
142   N6110_EnableDisplayOutput,
143   N6110_DisableDisplayOutput,
144   N6110_EnableCellBroadcast,
145   N6110_DisableCellBroadcast,
146   N6110_ReadCellBroadcast,
147   N6110_PlayTone,
148   N6110_GetProductProfileSetting,
149   N6110_SetProductProfileSetting,
150   N6110_GetOperatorName,
151   N6110_SetOperatorName,
152   N6110_GetVoiceMailbox,  N6110_Tests,
153   N6110_SimlockInfo,
154   UNIMPLEMENTED,                 //GetCalendarNotesInfo
155   N6110_GetSMSFolders,
156   N6110_ResetPhoneSettings,
157   N7110_GetWAPBookmark,
158   N7110_SetWAPBookmark,
159   N7110_GetWAPSettings,
160   N6110_CallDivert,
161   N6110_AnswerCall,
162 #else /* UCLINUX */
163   NULL,
164   NULL,
165   NULL,
166   NULL,
167   NULL,
168   NULL,
169   NULL,
170   NULL,
171   NULL,
172   NULL,
173   NULL,
174   NULL,  NULL,
175   NULL,
176   NULL,                 //GetCalendarNotesInfo
177   NULL,
178   NULL,
179   NULL,
180   NULL,
181   NULL,
182   NULL,
183   NULL,
184 #endif /* UCLINUX */
185   N6110_GetManufacturer
186 };
187
188 /* Mobile phone information */
189
190 GSM_Information N6110_Information = {
191   "3210|3310|3330|5110|5130|5190|6110|6130|6150|6190|8210|8850",
192      /* Supported models in FBUS */
193   "3210|3310|3330|5110|5130|5190|6110|6130|6150|6190|8210|8850",
194      /* Supported models in MBUS */
195   "6110|6130|6150|8210|8850",
196      /* Supported models in FBUS over infrared */
197   "",
198      /* Supported models in FBUS over DLR3 */
199   "",
200      /* AT commands */
201   "8210|8850",
202      /* infrared sockets */
203   "6110|6130|6150|8210|8850",
204      /* Supported models in FBUS over infrared with Tekram device */  
205   4,                     /* Max RF Level */
206   0,                     /* Min RF Level */
207   GRF_Arbitrary,         /* RF level units */
208   4,                     /* Max Battery Level */
209   0,                     /* Min Battery Level */
210   GBU_Arbitrary,         /* Battery level units */
211   GDT_DateTime,          /* Have date/time support */
212   GDT_TimeOnly,          /* Alarm supports time only */
213   1                      /* Only one alarm available */
214 };
215
216 #ifdef DEBUG
217 static const char *N6110_MemoryType_String [] = {
218   "",   /* 0x00 */
219   "MT", /* 0x01 */
220   "ME", /* 0x02 */
221   "SM", /* 0x03 */
222   "FD", /* 0x04 */
223   "ON", /* 0x05 */
224   "EN", /* 0x06 */
225   "DC", /* 0x07 */
226   "RC", /* 0x08 */
227   "MC", /* 0x09 */
228 };
229 #endif /* DEBUG */
230
231 /* Magic bytes from the phone. */
232 static unsigned char MagicBytes[4] = { 0x00, 0x00, 0x00, 0x00 };
233
234 /* For DisplayOutput */
235 #ifndef UCLINUX
236 static char               PhoneScreen[5+1][27+1];
237 static int                OldX=1000,OldY=0,NewX=0,NewY=0;
238 #endif /* UCLINUX */
239
240 void N6110_ReplyEnableExtendedCommands(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
241
242 #ifdef DEBUG
243   fprintf(stdout, _("Message: Answer for EnableExtendedSecurityCommands frame, meaning not known :-(\n"));
244 #endif /* DEBUG */
245
246   CurrentEnableExtendedCommandsError=GE_NONE;   
247 }
248
249 /* If you set make some things (for example,
250    change Security Code from phone's menu, disable and enable
251    phone), it won't answer for 0x40 frame - you won't be able
252    to play tones, get netmonitor, etc.
253
254    This function do thing called "Enabling extended security commands" -
255    it enables 0x40 frame functions.
256
257    This frame can also some other things - see below */
258 GSM_Error N6110_EnableExtendedCommands (unsigned char status)
259 {
260   unsigned char req[4] = { 0x00,
261                            0x01,0x64, /* Enable extended commands request */
262                            0x01 };    /* 0x01 - on, 0x00 - off,
263                                          0x03 & 0x04 - soft & hard reset,
264                                          0x06 - CONTACT SERVICE */
265
266   /* 0x06 MAKES CONTACT SERVICE! BE CAREFULL! */
267   /* When use 0x03 and had during session changed time & date
268      some phones (like 6150 or 6210) can ask for time & date after reset
269      or disable clock on the screen */
270   if (status!=0x06) req[3] = status;
271
272   return NULL_SendMessageSequence
273     (50, &CurrentEnableExtendedCommandsError, 4, 0x40, req);
274 }
275
276 void N6110_ReplyIMEI(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
277
278 #if defined WIN32 || !defined HAVE_SNPRINTF
279   sprintf(Current_IMEI, "%s", MessageBuffer+4);
280 #else
281   snprintf(Current_IMEI, GSM_MAX_IMEI_LENGTH, "%s", MessageBuffer+4);
282 #endif
283
284 #ifdef DEBUG
285   fprintf(stdout, _("Message: IMEI %s received\n"),Current_IMEI);
286 #endif
287
288   CurrentGetIMEIError=GE_NONE;       
289 }
290
291 GSM_Error N6110_SendIMEIFrame()
292 {
293   unsigned char req[4] = {0x00, 0x01, 0x66, 0x00};  
294
295   GSM_Error error;
296
297   error=N6110_EnableExtendedCommands(0x01);
298   if (error!=GE_NONE) return error;
299   
300   return NULL_SendMessageSequence (20, &CurrentGetIMEIError, 4, 0x40, req);
301 }
302
303 void N6110_ReplyHW(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
304
305   int i, j;
306     
307   if (MessageBuffer[3]==0x05) {
308
309 #ifdef DEBUG
310     fprintf(stdout,_("Message: Hardware version received: "));
311 #endif
312
313     j=strlen(Current_Revision);
314     Current_Revision[j++]=',';
315     Current_Revision[j++]=' ';
316     Current_Revision[j++]='H';
317     Current_Revision[j++]='W';
318             
319     for (i=5;i<9;i++) {
320 #ifdef DEBUG
321       fprintf(stdout,_("%c"), MessageBuffer[i]);
322 #endif
323       Current_Revision[j++]=MessageBuffer[i];
324     }
325
326 #ifdef DEBUG
327     fprintf(stdout,_("\n"));
328 #endif
329
330     CurrentGetHWError=GE_NONE;
331   }
332 }
333
334 GSM_Error N6110_SendHWFrame()
335 {
336   unsigned char req[4] = {0x00, 0x01, 0xc8, 0x05};  
337
338   GSM_Error error;
339
340   error=N6110_EnableExtendedCommands(0x01);
341   if (error!=GE_NONE) return error;
342   
343   return NULL_SendMessageSequence (20, &CurrentGetHWError, 4, 0x40, req);
344 }
345
346 void N6110_ReplyID(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
347
348   int i, j;
349  
350 #ifdef DEBUG
351   fprintf(stdout, _("Message: Mobile phone model identification received:\n"));
352   fprintf(stdout, _("   Firmware: "));
353 #endif
354
355   strcpy(Current_Revision,"SW");
356     
357   i=6;j=2;
358   while (MessageBuffer[i]!=0x0a) {
359     Current_Revision[j]=MessageBuffer[i];
360 #ifdef DEBUG
361     fprintf(stdout, _("%c"),MessageBuffer[i]);
362 #endif
363     if (j==GSM_MAX_REVISION_LENGTH-1) {
364 #ifdef DEBUG
365       fprintf(stderr,_("ERROR: increase GSM_MAX_REVISION_LENGTH!\n"));
366 #endif  
367       break;
368     }
369     j++;
370     i++;
371   }
372   Current_Revision[j+1]=0;
373
374 #ifdef DEBUG
375   fprintf(stdout, _("\n   Firmware date: "));
376 #endif
377
378   i++;
379   while (MessageBuffer[i]!=0x0a) {
380 #ifdef DEBUG
381     fprintf(stdout, _("%c"),MessageBuffer[i]);
382 #endif
383     i++;
384   }
385
386 #ifdef DEBUG
387   fprintf(stdout, _("\n   Model: "));
388 #endif /* DEBUG */
389
390   i++;j=0;
391   while (MessageBuffer[i]!=0x0a) {
392     Current_Model[j]=MessageBuffer[i];
393 #ifdef DEBUG
394     fprintf(stdout, _("%c"),MessageBuffer[i]);
395 #endif
396     if (j==GSM_MAX_MODEL_LENGTH-1) {
397 #ifdef DEBUG
398       fprintf(stderr,_("ERROR: increase GSM_MAX_MODEL_LENGTH!\n"));
399 #endif  
400       break;
401     }
402     j++;
403     i++;
404   }
405   Current_Model[j+1]=0;
406
407 #ifdef DEBUG
408   fprintf(stdout, _("\n"));
409 #endif /* DEBUG */
410     
411   CurrentMagicError=GE_NONE;
412 }
413
414 GSM_Error N6110_SendIDFrame()
415 {
416   unsigned char req[5] = {N6110_FRAME_HEADER, 0x03, 0x00};  
417
418   return NULL_SendMessageSequence (50, &CurrentMagicError, 5, 0xd1, req);
419 }
420
421 /* This function send the status request to the phone. */
422 /* Seems to be ignored in N3210 */
423 GSM_Error N6110_SendStatusRequest(void)
424 {
425   unsigned char req[] = {N6110_FRAME_HEADER, 0x01};
426
427   Protocol->SendMessage(4, 0x04, req);
428
429   return (GE_NONE);
430 }
431
432 static void N6110_ReplyGetAuthentication(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
433
434   LIVE;
435
436 #if defined WIN32 || !defined HAVE_SNPRINTF
437   sprintf(Current_IMEI, "%s", MessageBuffer+9);
438   sprintf(Current_Model, "%s", MessageBuffer+25);
439   sprintf(Current_Revision, "SW%s, HW%s", MessageBuffer+44, MessageBuffer+39);
440 #else
441   snprintf(Current_IMEI, GSM_MAX_IMEI_LENGTH, "%s", MessageBuffer+9);
442   snprintf(Current_Model, GSM_MAX_MODEL_LENGTH, "%s", MessageBuffer+25);
443   snprintf(Current_Revision, GSM_MAX_REVISION_LENGTH, "SW%s, HW%s", MessageBuffer+44, MessageBuffer+39);
444 #endif
445
446 #ifdef DEBUG
447   fprintf(stdout, _("Message: Mobile phone identification received:\n"));
448   fprintf(stdout, _("   IMEI: %s\n"), Current_IMEI);
449   fprintf(stdout, _("   Model: %s\n"), Current_Model);
450   fprintf(stdout, _("   Production Code: %s\n"), MessageBuffer+31);
451   fprintf(stdout, _("   HW: %s\n"), MessageBuffer+39);
452   fprintf(stdout, _("   Firmware: %s\n"), MessageBuffer+44);
453
454   /* These bytes are probably the source of the "Accessory not connected"
455      messages on the phone when trying to emulate NCDS... I hope....
456      UPDATE: of course, now we have the authentication algorithm. */
457   fprintf(stdout, _("   Magic bytes: %02x %02x %02x %02x\n"), MessageBuffer[50], MessageBuffer[51], MessageBuffer[52], MessageBuffer[53]);
458 #endif /* DEBUG */
459
460   MagicBytes[0]=MessageBuffer[50];
461   MagicBytes[1]=MessageBuffer[51];
462   MagicBytes[2]=MessageBuffer[52];
463   MagicBytes[3]=MessageBuffer[53];
464
465   CurrentMagicError=GE_NONE;
466 }
467
468 /* This function provides Nokia authentication protocol.
469
470    This code is written specially for gnokii project by Odinokov Serge.
471    If you have some special requests for Serge just write him to
472    apskaita@post.omnitel.net or serge@takas.lt
473
474    Reimplemented in C by Pavel Janík ml.
475
476    Nokia authentication protocol is used in the communication between Nokia
477    mobile phones (e.g. Nokia 6110) and Nokia Cellular Data Suite software,
478    commercially sold by Nokia Corp.
479
480    The authentication scheme is based on the token send by the phone to the
481    software. The software does it's magic (see the function
482    FB61_GetNokiaAuth()) and returns the result back to the phone. If the
483    result is correct the phone responds with the message "Accessory
484    connected!" displayed on the LCD. Otherwise it will display "Accessory not
485    supported" and some functions will not be available for use.
486
487    The specification of the protocol is not publicly available, no comment. */
488 static void N6110_GetNokiaAuth(unsigned char *Imei, unsigned char *MagicBytes, unsigned char *MagicResponse)
489 {
490
491   int i, j, CRC=0;
492
493   /* This is our temporary working area. */
494
495   unsigned char Temp[16];
496
497   /* Here we put FAC (Final Assembly Code) and serial number into our area. */
498
499   Temp[0]  = Imei[6];
500   Temp[1]  = Imei[7];
501   Temp[2]  = Imei[8];
502   Temp[3]  = Imei[9];
503   Temp[4]  = Imei[10];
504   Temp[5]  = Imei[11];
505   Temp[6]  = Imei[12];
506   Temp[7]  = Imei[13];
507
508   /* And now the TAC (Type Approval Code). */
509
510   Temp[8]  = Imei[2];
511   Temp[9]  = Imei[3];
512   Temp[10] = Imei[4];
513   Temp[11] = Imei[5];
514
515   /* And now we pack magic bytes from the phone. */
516
517   Temp[12] = MagicBytes[0];
518   Temp[13] = MagicBytes[1];
519   Temp[14] = MagicBytes[2];
520   Temp[15] = MagicBytes[3];
521
522   for (i=0; i<=11; i++)
523     if (Temp[i + 1]& 1)
524       Temp[i]<<=1;
525
526   switch (Temp[15] & 0x03) {
527
528   case 1:
529   case 2:
530     j = Temp[13] & 0x07;
531
532     for (i=0; i<=3; i++)
533       Temp[i+j] ^= Temp[i+12];
534
535     break;
536
537   default:
538     j = Temp[14] & 0x07;
539
540     for (i=0; i<=3; i++)
541       Temp[i + j] |= Temp[i + 12];
542   }
543
544   for (i=0; i<=15; i++)
545     CRC ^= Temp[i];
546
547   for (i=0; i<=15; i++) {
548
549     switch (Temp[15 - i] & 0x06) {
550
551     case 0:
552       j = Temp[i] | CRC;
553       break;
554
555     case 2:
556     case 4:
557       j = Temp[i] ^ CRC;
558       break;
559
560     case 6:
561       j = Temp[i] & CRC;
562       break;
563     }
564   
565     if (j == CRC)
566       j = 0x2c;
567
568     if (Temp[i] == 0)
569       j = 0;
570
571     MagicResponse[i] = j;
572
573   }
574 }
575
576 static GSM_Error N6110_Authentication()
577 {
578   unsigned char connect1[] = {N6110_FRAME_HEADER, 0x0d, 0x00, 0x00, 0x02};
579   unsigned char connect2[] = {N6110_FRAME_HEADER, 0x20, 0x02};
580   unsigned char connect3[] = {N6110_FRAME_HEADER, 0x0d, 0x01, 0x00, 0x02};
581   unsigned char connect4[] = {N6110_FRAME_HEADER, 0x10};
582   
583   unsigned char magic_connect[] = {N6110_FRAME_HEADER,
584   0x12,
585
586   /* The real magic goes here ... These bytes are filled in with the
587      function N6110_GetNokiaAuth(). */
588
589   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
591
592   /* NOKIA&GNOKII Accessory */
593
594   0x4e, 0x4f, 0x4b, 0x49, 0x41, 0x26, 0x4e, 0x4f, 0x4b, 0x49, 0x41, 0x20,
595   0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x79,
596   
597   0x00, 0x00, 0x00, 0x00};
598
599   unsigned char req3_55[]  = { N6110_FRAME_HEADER, 0x42,0x05,0x01,
600                                0x07,0xa2,0x88,0x81,0x21,0x55,0x63,0xa8,0x00,0x00,
601                                0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80 };
602   unsigned char req3[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x01,
603                                0x07,0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
604                                0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80 };
605   unsigned char unknown_05[] = {N6110_FRAME_HEADER, 0x05};
606
607 #ifdef DEBUG
608   fprintf(stdout,_("Making authentication!\n"));
609 #endif
610
611   usleep(100); Protocol->SendMessage(7, 0x02, connect1);
612   usleep(100); Protocol->SendMessage(5, 0x02, connect2);
613   usleep(100); Protocol->SendMessage(7, 0x02, connect3);
614       
615   usleep(100); Protocol->SendMessage(sizeof(req3_55), 0x01, req3_55);   /* Lace */
616
617   CurrentMagicError = GE_BUSY;
618
619   usleep(100); Protocol->SendMessage(4, 0x64, connect4);
620
621   usleep(100); Protocol->SendMessage(sizeof(req3_55), 0x01, req3_55);   /* Lace */
622   usleep(100); Protocol->SendMessage(sizeof(req3), 0x01, req3); /* Lace */
623
624   if (NULL_WaitUntil(50,&CurrentMagicError)!=GE_NONE) return GE_TIMEOUT;
625
626   N6110_GetNokiaAuth(Current_IMEI, MagicBytes, magic_connect+4);
627
628   Protocol->SendMessage(45, 0x64, magic_connect);
629
630   usleep(100); Protocol->SendMessage(4, 0x04, unknown_05); /* Lace */
631
632 #ifdef DEBUG
633   fprintf(stdout,_("End of authentication!\n"));
634 #endif
635
636   return GE_NONE;
637 }
638
639 /* Initialise variables and state machine. */
640 GSM_Error N6110_Initialise(char *port_device, char *initlength,
641                           GSM_ConnectionType connection,
642                           void (*rlp_callback)(RLP_F96Frame *frame))
643 {
644   unsigned char init_char = N6110_SYNC_BYTE;
645 #ifndef UCLINUX
646   unsigned char end_init_char = N6110_IR_END_SYNC_BYTE;
647 #endif /* UCLINUX */
648
649   int count;
650   int InitLength;
651   
652   if (Protocol->Initialise(port_device,initlength,connection,rlp_callback)!=GE_NONE)
653   {
654     return GE_NOTSUPPORTED;
655   }
656
657   switch (CurrentConnectionType) {
658 #ifndef UCLINUX
659     case GCT_Irda:
660     case GCT_MBUS:
661       /* We don't think about authentication in Irda, because
662          AFAIK there are no phones working over sockets
663          and having authentication. In MBUS it doesn't work */
664       usleep(100);
665
666       if (N6110_SendIDFrame()!=GE_NONE) return GE_TIMEOUT;
667     
668       if (N6110_SendIMEIFrame()!=GE_NONE) return GE_TIMEOUT;    
669
670       if (N6110_SendHWFrame()!=GE_NONE) return GE_TIMEOUT;    
671
672       CurrentLinkOK = true;                                 
673       break;
674 #endif /* UCLINUX */
675       
676     case GCT_FBUS:
677 #ifndef UCLINUX
678     case GCT_Infrared:
679     case GCT_Tekram:
680 #endif /* UCLINUX */
681       InitLength = atoi(initlength);
682
683       if ((strcmp(initlength, "default") == 0) || (InitLength == 0)) {
684         InitLength = 250;       /* This is the usual value, lower may work. */
685       }
686
687 #ifndef UCLINUX
688       if (CurrentConnectionType==GCT_Infrared ||
689           CurrentConnectionType==GCT_Tekram) {
690 #ifdef DEBUG
691         fprintf(stdout,_("Setting infrared for FBUS communication...\n"));
692 #endif
693         device_changespeed(9600);
694       }
695 #endif /* UCLINUX */
696
697 #ifdef DEBUG
698       fprintf(stdout,_("Writing init chars...."));
699 #endif
700
701       /* Initialise link with phone or what have you */
702       /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
703          empirical. */
704       for (count = 0; count < InitLength; count ++) {
705 #ifndef UCLINUX
706         if (CurrentConnectionType!=GCT_Infrared &&
707             CurrentConnectionType!=GCT_Tekram)
708 #endif /* UCLINUX */
709                                         usleep(100);
710         Protocol->WritePhone(1,&init_char);
711       }
712
713 #ifndef UCLINUX
714       if (CurrentConnectionType==GCT_Infrared ||
715           CurrentConnectionType==GCT_Tekram)      {
716         Protocol->WritePhone(1,&end_init_char);
717         usleep(200000);
718       }
719 #endif /* UCLINUX */
720
721 #ifdef DEBUG
722       fprintf(stdout,_("Done\n"));  
723 #endif
724
725 #ifndef UCLINUX
726       if (CurrentConnectionType==GCT_Infrared ||
727           CurrentConnectionType==GCT_Tekram)      {
728         device_changespeed(115200);    
729       }
730 #endif /* UCLINUX */
731
732       N6110_SendStatusRequest();
733     
734       usleep(100);
735
736       if (N6110_SendIDFrame()!=GE_NONE) return GE_TIMEOUT;
737     
738       /* N51xx/61xx have something called authentication.
739          After making it phone display "Accessory connected"
740          and probably give access to some function (I'm not too sure about it !)
741          Anyway, I make it now for N51xx/61xx */
742 #if 1
743       if (GetModelFeature (FN_AUTHENTICATION)!=0)
744 #else
745       if (0/*Lace-hack:GetModelFeature (FN_AUTHENTICATION)!=0*/)
746 #endif
747         {
748         if (N6110_Authentication()!=GE_NONE) return GE_TIMEOUT;
749       } else {        /* No authentication */
750         if (N6110_SendIMEIFrame()!=GE_NONE) return GE_TIMEOUT;    
751
752         if (N6110_SendHWFrame()!=GE_NONE) return GE_TIMEOUT;    
753       }
754       
755       break;
756     default:
757 #ifdef DEBUG
758       fprintf(stdout,_("Unknown connection type in n6110.c!\n"));
759 #endif
760       break;
761   }
762
763   return (GE_NONE);
764 }
765
766 /* This function translates GMT_MemoryType to N6110_MEMORY_xx */
767 int N6110_GetMemoryType(GSM_MemoryType memory_type)
768 {
769
770   int result;
771
772   switch (memory_type) {
773
774      case GMT_MT: result = N6110_MEMORY_MT; break;
775      case GMT_ME: result = N6110_MEMORY_ME; break;
776      case GMT_SM: result = N6110_MEMORY_SM; break;
777      case GMT_FD: result = N6110_MEMORY_FD; break;
778      case GMT_ON: result = N6110_MEMORY_ON; break;
779      case GMT_EN: result = N6110_MEMORY_EN; break;
780      case GMT_DC: result = N6110_MEMORY_DC; break;
781      case GMT_RC: result = N6110_MEMORY_RC; break;
782      case GMT_MC: result = N6110_MEMORY_MC; break;
783      default    : result = N6110_MEMORY_XX;
784
785    }
786
787    return (result);
788 }
789
790 #ifndef UCLINUX
791
792 void N6110_ReplyCallDivert(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
793
794   switch (MessageBuffer[3]) {
795
796   case 0x02:
797
798 #ifdef DEBUG
799     fprintf(stdout, _("Message: Call divert status received\n"));
800     fprintf(stdout, _("   Divert type: "));
801     switch (MessageBuffer[6]) {
802       case 0x43: fprintf(stdout, _("when busy"));break;
803       case 0x3d: fprintf(stdout, _("when not answered"));break;
804       case 0x3e: fprintf(stdout, _("when phone off or no coverage"));break;
805       case 0x15: fprintf(stdout, _("all types of diverts"));break; //?
806       case 0x02: fprintf(stdout, _("all types of diverts"));break; //?
807       default:   fprintf(stdout, _("unknown %i"),MessageBuffer[6]);break;
808     }
809     fprintf(stdout, _("\n   Calls type : "));
810     if (MessageBuffer[6]==0x02)
811       fprintf(stdout, _("voice, fax & data")); //?
812     else {
813       switch (MessageBuffer[8]) {
814         case 0x0b: fprintf(stdout, _("voice"));break;
815         case 0x0d: fprintf(stdout, _("fax"));break;
816         case 0x19: fprintf(stdout, _("data"));break;
817         default:   fprintf(stdout, _("unknown %i"),MessageBuffer[8]);break;
818       }
819     }
820     fprintf(stdout, _("\n"));     
821     if (MessageBuffer[10]==0x01) {
822       fprintf(stdout, _("   Status     : active\n"));
823       fprintf(stdout, _("   Timeout    : %i seconds\n"),MessageBuffer[45]);
824       fprintf(stdout, _("   Number     : %s\n"),GSM_UnpackSemiOctetNumber(MessageBuffer+12,true));
825     } else {
826       fprintf(stdout, _("   Status     : deactivated\n"));     
827     }
828 #endif /* DEBUG */
829  
830     switch (MessageBuffer[6]) {
831       case 0x43: CurrentCallDivert->DType=GSM_CDV_Busy;break;
832       case 0x3d: CurrentCallDivert->DType=GSM_CDV_NoAnswer;break;
833       case 0x3e: CurrentCallDivert->DType=GSM_CDV_OutOfReach;break;
834       case 0x15: CurrentCallDivert->DType=GSM_CDV_AllTypes;break; //?
835       case 0x02: CurrentCallDivert->DType=GSM_CDV_AllTypes;break; //?
836     }
837
838     if (MessageBuffer[6]==0x02) //?
839       CurrentCallDivert->CType=GSM_CDV_AllCalls;
840     else {
841       switch (MessageBuffer[8]) {
842         case 0x0b: CurrentCallDivert->CType=GSM_CDV_VoiceCalls;break;
843         case 0x0d: CurrentCallDivert->CType=GSM_CDV_FaxCalls;  break;
844         case 0x19: CurrentCallDivert->CType=GSM_CDV_DataCalls; break;
845       }
846     }
847
848     if (MessageBuffer[10]==0x01) {
849       CurrentCallDivert->Enabled=true;
850       CurrentCallDivert->Timeout=MessageBuffer[45];
851       strcpy(CurrentCallDivert->Number,GSM_UnpackSemiOctetNumber(MessageBuffer+12,true));
852     } else {
853       CurrentCallDivert->Enabled=false;
854     }
855
856     CurrentCallDivertError=GE_NONE;
857     break;
858
859   case 0x03:
860 #ifdef DEBUG
861     fprintf(stdout, _("Message: Call divert status receiving error ?\n"));
862 #endif
863     CurrentCallDivertError=GE_UNKNOWN;
864     break;
865   }
866 }
867
868 GSM_Error N6110_CallDivert(GSM_CallDivert *cd)
869 {
870   char req[55] = { N6110_FRAME_HEADER, 0x01,
871                                        0x00, /* operation */
872                                        0x00,
873                                        0x00, /* divert type */
874                                        0x00, /* call type */
875                                        0x00 };
876   GSM_Error error;
877
878   int length = 0x09;
879
880   switch (cd->Operation) {
881     case GSM_CDV_Register:
882     case GSM_CDV_Enable:
883       req[4] = 0x03;
884       req[8] = 0x01;
885       req[29]= GSM_PackSemiOctetNumber(cd->Number, req + 9, false);
886       req[52]= cd->Timeout;
887       length = 55;
888       break;
889     case GSM_CDV_Erasure:
890     case GSM_CDV_Disable:
891       req[4] = 0x04;
892       break;
893     case GSM_CDV_Query:
894       req[4] = 0x05;
895       break;
896     default:
897       return GE_NOTIMPLEMENTED;
898   }
899
900   switch (cd->DType) {
901     case GSM_CDV_AllTypes  : req[6] = 0x15; break;
902     case GSM_CDV_Busy      : req[6] = 0x43; break;
903     case GSM_CDV_NoAnswer  : req[6] = 0x3d; break;
904     case GSM_CDV_OutOfReach: req[6] = 0x3e; break;
905     default:                 return GE_NOTIMPLEMENTED;
906   }
907
908   if ((cd->DType == GSM_CDV_AllTypes) &&
909       (cd->CType == GSM_CDV_AllCalls))
910     req[6] = 0x02;
911
912   switch (cd->CType) {
913     case GSM_CDV_AllCalls  :                break;
914     case GSM_CDV_VoiceCalls: req[7] = 0x0b; break;
915     case GSM_CDV_FaxCalls  : req[7] = 0x0d; break;
916     case GSM_CDV_DataCalls : req[7] = 0x19; break;
917     default:                 return GE_NOTIMPLEMENTED;
918   }
919
920   CurrentCallDivert = cd;
921
922   error=NULL_SendMessageSequence
923     (100, &CurrentCallDivertError, length, 0x06, req);
924
925   CurrentCallDivert = NULL;
926
927   return error;
928 }
929
930 GSM_Error N6110_Tests()
931 {
932   unsigned char buffer[3]={0x00,0x01,0xcf};
933   unsigned char buffer3[8]={0x00,0x01,0xce,0x1d,0xfe,0x23,0x00,0x00};
934   
935   GSM_Error error;
936
937   error=N6110_EnableExtendedCommands(0x01);
938   if (error!=GE_NONE) return error;
939
940   //make almost all tests
941   Protocol->SendMessage(8, 0x40, buffer3);
942
943   while (GSM->Initialise(PortDevice, "50", CurrentConnectionType, CurrentRLP_RXCallback)!=GE_NONE) {};
944
945   sleep(2);
946
947   return NULL_SendMessageSequence
948     (200, &CurrentNetworkInfoError, 3, 0x40, buffer);  
949 }
950
951 void N6110_DisplayTestsInfo(u8 *MessageBuffer) {
952
953   int i;
954
955   CurrentNetworkInfoError=GE_NONE;
956
957   for (i=0;i<MessageBuffer[3];i++) {
958     switch (i) {
959       case 0: fprintf(stdout,_("Unknown(%i)              "),i);break;
960       case 1: fprintf(stdout,_("MCU ROM checksum        "));break;
961       case 2: fprintf(stdout,_("MCU RAM interface       "));break;
962       case 3: fprintf(stdout,_("MCU RAM component       "));break;
963       case 4: fprintf(stdout,_("MCU EEPROM interface    "));break;
964       case 5: fprintf(stdout,_("MCU EEPROM component    "));break;
965       case 6: fprintf(stdout,_("Real Time Clock battery "));break;
966       case 7: fprintf(stdout,_("CCONT interface         "));break;
967       case 8: fprintf(stdout,_("AD converter            "));break;
968       case 9: fprintf(stdout,_("SW Reset                "));break;
969       case 10:fprintf(stdout,_("Power Off               "));break;
970       case 11:fprintf(stdout,_("Security Data           "));break;
971       case 12:fprintf(stdout,_("EEPROM Tune checksum    "));break;
972       case 13:fprintf(stdout,_("PPM checksum            "));break;
973       case 14:fprintf(stdout,_("MCU download DSP        "));break;
974       case 15:fprintf(stdout,_("DSP alive               "));break;
975       case 16:fprintf(stdout,_("COBBA serial            "));break;
976       case 17:fprintf(stdout,_("COBBA paraller          "));break;
977       case 18:fprintf(stdout,_("EEPROM security checksum"));break;
978       case 19:fprintf(stdout,_("PPM validity            "));break;
979       case 20:fprintf(stdout,_("Warranty state          "));break;
980       case 21:fprintf(stdout,_("Simlock check           "));break;
981       case 22:fprintf(stdout,_("IMEI check?             "));break;//from PC-Locals.is OK?
982       default:fprintf(stdout,_("Unknown(%i)             "),i);break;
983     }
984     switch (MessageBuffer[4+i]) {
985       case 0:   fprintf(stdout,_(" : done, result OK"));break;
986       case 0xff:fprintf(stdout,_(" : not done, result unknown"));break;
987       case 254: fprintf(stdout,_(" : done, result NOT OK"));break;
988       default:  fprintf(stdout,_(" : result unknown(%i)"),MessageBuffer[4+i]);break;
989     }
990     fprintf(stdout,_("\n"));
991   }
992 }
993
994 void N6110_ReplySimlockInfo(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
995
996   int i, j;
997   
998   char uni[100];
999     
1000 #ifdef DEBUG
1001   fprintf(stdout, _("Message: Simlock info received\n"));
1002
1003   j=0;
1004   for (i=0; i < 12; i++)
1005   {
1006     if (j<24) {
1007       fprintf(stdout,_("%c"), ('0' + (MessageBuffer[9+i] >> 4)));
1008       j++;
1009     }
1010     if (j==5 || j==15) fprintf(stdout, _("\n"));
1011     if (j!=15) {
1012       if (j<24) {
1013         fprintf(stdout,_("%c"), ('0' + (MessageBuffer[9+i] & 0x0f)));
1014         j++;
1015       }
1016     } else j++;
1017     if (j==20 || j==24) fprintf(stdout, _("\n"));
1018   }
1019       
1020   if ((MessageBuffer[6] & 1) == 1) fprintf(stdout,_("lock 1 closed\n"));
1021   if ((MessageBuffer[6] & 2) == 2) fprintf(stdout,_("lock 2 closed\n"));
1022   if ((MessageBuffer[6] & 4) == 4) fprintf(stdout,_("lock 3 closed\n"));
1023   if ((MessageBuffer[6] & 8) == 8) fprintf(stdout,_("lock 4 closed\n"));
1024
1025   /* I'm not sure here at all */
1026   if ((MessageBuffer[5] & 1) == 1) fprintf(stdout,_("lock 1 - user\n"));
1027   if ((MessageBuffer[5] & 2) == 2) fprintf(stdout,_("lock 2 - user\n"));
1028   if ((MessageBuffer[5] & 4) == 4) fprintf(stdout,_("lock 3 - user\n"));
1029   if ((MessageBuffer[5] & 8) == 8) fprintf(stdout,_("lock 4 - user\n"));
1030
1031   fprintf(stdout,_("counter for lock1: %i\n"),MessageBuffer[21]);
1032   fprintf(stdout,_("counter for lock2: %i\n"),MessageBuffer[22]);
1033   fprintf(stdout,_("counter for lock3: %i\n"),MessageBuffer[23]);
1034   fprintf(stdout,_("counter for lock4: %i\n"),MessageBuffer[24]);
1035
1036 #endif
1037
1038   j=0;
1039   for (i=0; i < 12; i++)
1040   {
1041     if (j<24) {
1042       uni[j]='0' + (MessageBuffer[9+i] >> 4);
1043       j++;
1044     }
1045     if (j!=15) {
1046       if (j<24) {
1047         uni[j]='0' + (MessageBuffer[9+i] & 0x0f);
1048         j++;
1049       }
1050     } else j++;
1051   }
1052
1053   strncpy(CurrentSimLock->simlocks[0].data,uni,5);
1054   CurrentSimLock->simlocks[0].data[5]=0;
1055   strncpy(CurrentSimLock->simlocks[3].data,uni+5,10);
1056   CurrentSimLock->simlocks[3].data[10]=0;
1057   strncpy(CurrentSimLock->simlocks[1].data,uni+16,4);
1058   CurrentSimLock->simlocks[1].data[4]=0;
1059   strncpy(CurrentSimLock->simlocks[2].data,uni+20,4);
1060   CurrentSimLock->simlocks[2].data[4]=0;                                    
1061
1062   CurrentSimLock->simlocks[0].enabled=((MessageBuffer[6] & 1) == 1);
1063   CurrentSimLock->simlocks[1].enabled=((MessageBuffer[6] & 2) == 2);
1064   CurrentSimLock->simlocks[2].enabled=((MessageBuffer[6] & 4) == 4);
1065   CurrentSimLock->simlocks[3].enabled=((MessageBuffer[6] & 8) == 8);
1066
1067   CurrentSimLock->simlocks[0].factory=((MessageBuffer[5] & 1) != 1);
1068   CurrentSimLock->simlocks[1].factory=((MessageBuffer[5] & 2) != 2);
1069   CurrentSimLock->simlocks[2].factory=((MessageBuffer[5] & 4) != 4);
1070   CurrentSimLock->simlocks[3].factory=((MessageBuffer[5] & 8) != 8);
1071
1072   CurrentSimLock->simlocks[0].counter=MessageBuffer[21];
1073   CurrentSimLock->simlocks[1].counter=MessageBuffer[22];
1074   CurrentSimLock->simlocks[2].counter=MessageBuffer[23];
1075   CurrentSimLock->simlocks[3].counter=MessageBuffer[24];
1076
1077   CurrentSimlockInfoError=GE_NONE;
1078 }
1079
1080 GSM_Error N6110_SimlockInfo(GSM_AllSimlocks *siml)
1081 {
1082   GSM_Error error;
1083   unsigned char req[] = {0x00,0x01,0x8a,0x00};
1084   error=N6110_EnableExtendedCommands(0x01);
1085   if (error!=GE_NONE) return error;
1086
1087   CurrentSimLock=siml;
1088  
1089   return NULL_SendMessageSequence (50, &CurrentSimlockInfoError, 4, 0x40, req);  
1090 }
1091
1092 void N6110_ReplyResetPhoneSettings(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1093
1094 #ifdef DEBUG
1095   fprintf(stdout, _("Message: Resetting phone settings\n"));
1096 #endif /* DEBUG */
1097
1098   CurrentResetPhoneSettingsError=GE_NONE;
1099 }
1100
1101 GSM_Error N6110_ResetPhoneSettings()
1102 {
1103   GSM_Error error;
1104   unsigned char req[] = {0x00,0x01,0x65,0x08,0x00};  
1105   error=N6110_EnableExtendedCommands(0x01);
1106   if (error!=GE_NONE) return error;
1107
1108   return NULL_SendMessageSequence
1109     (50, &CurrentResetPhoneSettingsError, 5, 0x40, req);  
1110 }
1111
1112 #endif /* UCLINUX */
1113
1114 GSM_Error N6110_GetManufacturer(char *manufacturer)
1115 {
1116         strcpy (manufacturer, "Nokia");
1117         return (GE_NONE);
1118 }
1119
1120 #ifndef UCLINUX
1121
1122 GSM_Error N6110_GetVoiceMailbox ( GSM_PhonebookEntry *entry)
1123 {
1124   unsigned char req[] = {N6110_FRAME_HEADER, 0x01, 0x00, 0x00, 0x00};
1125
1126   GSM_Error error;
1127   
1128   CurrentPhonebookEntry = entry;
1129
1130   req[4] = N6110_MEMORY_VOICE;
1131   req[5] = 0x00; /* Location - isn't important, but... */
1132
1133   error=NULL_SendMessageSequence
1134     (20, &CurrentPhonebookError, 7, 0x03, req);
1135     
1136   CurrentPhonebookEntry = NULL;
1137   
1138   return error;
1139 }
1140
1141 void N6110_ReplyGetOperatorName(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1142
1143   int i, count;
1144   
1145   GSM_Bitmap NullBitmap;
1146
1147   DecodeNetworkCode(MessageBuffer+5, NullBitmap.netcode);
1148   
1149   count=8;
1150
1151 #ifdef DEBUG
1152   fprintf(stdout, _("Message: Info about downloaded operator name received: %s network (for gnokii \"%s\", for phone \""),
1153           NullBitmap.netcode,
1154           GSM_GetNetworkName(NullBitmap.netcode));      
1155 #endif
1156       
1157   i=count;
1158   while (MessageBuffer[count]!=0) {
1159 #ifdef DEBUG
1160     fprintf(stdout,_("%c"),MessageBuffer[count]);
1161 #endif
1162     count++;
1163   }
1164       
1165  strcpy(CurrentGetOperatorNameNetwork->Code, NullBitmap.netcode);
1166  strncpy(CurrentGetOperatorNameNetwork->Name, MessageBuffer+i,count-i+1);
1167
1168 #ifdef DEBUG
1169   fprintf(stdout,_("\")\n"));
1170 #endif
1171           
1172   CurrentGetOperatorNameError=GE_NONE;
1173 }
1174
1175 GSM_Error N6110_GetOperatorName (GSM_Network *operator)
1176 {
1177   unsigned char req[] = { 0x00,0x01,0x8c,0x00};
1178
1179   GSM_Error error;
1180
1181   error=N6110_EnableExtendedCommands(0x01);
1182   if (error!=GE_NONE) return error;
1183
1184   CurrentGetOperatorNameNetwork = operator;
1185
1186   error=NULL_SendMessageSequence
1187     (20, &CurrentGetOperatorNameError, 4, 0x40, req);
1188
1189   CurrentGetOperatorNameNetwork = NULL;
1190   
1191   return error;
1192 }
1193
1194 void N6110_ReplySetOperatorName(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1195     
1196 #ifdef DEBUG
1197   fprintf(stdout, _("Message: Downloaded operator name changed\n"));
1198 #endif    
1199
1200   CurrentSetOperatorNameError=GE_NONE;      
1201 }
1202
1203 GSM_Error N6110_SetOperatorName (GSM_Network *operator)
1204 {
1205   unsigned char req[256] = { 0x00,0x01,0x8b,0x00,
1206                              0x00,0x00, /* MCC */
1207                              0x00};     /* MNC */
1208
1209   GSM_Error error;
1210
1211   error=N6110_EnableExtendedCommands(0x01);
1212   if (error!=GE_NONE) return error;
1213
1214   EncodeNetworkCode(req+4,operator->Code);
1215
1216   strncpy(req+7,operator->Name,200);
1217     
1218   return NULL_SendMessageSequence
1219     (20, &CurrentSetOperatorNameError, 8+strlen(operator->Name), 0x40, req);
1220 }
1221
1222 #endif /* UCLINUX */
1223
1224 static void N6110_ReplyGetMemoryStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1225
1226   switch (MessageBuffer[3]) {
1227
1228   case 0x08:
1229
1230 #ifdef DEBUG
1231     fprintf(stdout, _("Message: Memory status received:\n"));
1232
1233     fprintf(stdout, _("   Memory Type: %s\n"), N6110_MemoryType_String[MessageBuffer[4]]);
1234     fprintf(stdout, _("   Used: %d\n"), MessageBuffer[6]);
1235     fprintf(stdout, _("   Free: %d\n"), MessageBuffer[5]);
1236 #endif /* DEBUG */
1237
1238     CurrentMemoryStatus->Used = MessageBuffer[6];
1239     CurrentMemoryStatus->Free = MessageBuffer[5];
1240     CurrentMemoryStatusError = GE_NONE;
1241
1242     break;
1243
1244   case 0x09:
1245
1246 #ifdef DEBUG
1247     switch (MessageBuffer[4]) {
1248       case 0x6f:
1249         fprintf(stdout, _("Message: Memory status error, phone is probably powered off.\n"));break;
1250       case 0x7d:
1251         fprintf(stdout, _("Message: Memory status error, memory type not supported by phone model.\n"));break;
1252       case 0x8d:
1253         fprintf(stdout, _("Message: Memory status error, waiting for security code.\n"));break;
1254       default:
1255         fprintf(stdout, _("Message: Unknown Memory status error, subtype (MessageBuffer[4]) = %02x\n"),MessageBuffer[4]);break;
1256     }
1257 #endif
1258
1259     switch (MessageBuffer[4]) {
1260       case 0x6f:CurrentMemoryStatusError = GE_TIMEOUT;break;
1261       case 0x7d:CurrentMemoryStatusError = GE_INTERNALERROR;break;
1262       case 0x8d:CurrentMemoryStatusError = GE_INVALIDSECURITYCODE;break;
1263       default:break;
1264     }
1265
1266     break;
1267
1268   }
1269 }
1270
1271 /* This function is used to get storage status from the phone. It currently
1272    supports two different memory areas - internal and SIM. */
1273 GSM_Error N6110_GetMemoryStatus(GSM_MemoryStatus *Status)
1274 {
1275   unsigned char req[] = { N6110_FRAME_HEADER,
1276                           0x07, /* MemoryStatus request */
1277                           0x00  /* MemoryType */
1278                         };
1279
1280   GSM_Error error;
1281   
1282   CurrentMemoryStatus = Status;
1283
1284   req[4] = N6110_GetMemoryType(Status->MemoryType);
1285
1286   error=NULL_SendMessageSequence
1287     (20, &CurrentMemoryStatusError, 5, 0x03, req);
1288
1289   CurrentMemoryStatus = NULL;
1290
1291   return error;
1292 }
1293
1294 #ifndef UCLINUX
1295
1296 void N6110_ReplyGetNetworkInfo(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1297
1298   GSM_NetworkInfo NullNetworkInfo;
1299   
1300   /* Make sure we are expecting NetworkInfo frame */
1301   if (CurrentNetworkInfo && CurrentNetworkInfoError == GE_BUSY) {
1302 #ifdef DEBUG
1303     fprintf(stdout, _("Message: Network informations:\n"));
1304 #endif
1305   } else {
1306 #ifdef DEBUG
1307     fprintf(stdout, _("Message: Network informations not requested, but received:\n"));
1308 #endif
1309   }
1310       
1311   sprintf(NullNetworkInfo.NetworkCode, "%x%x%x %x%x", MessageBuffer[14] & 0x0f, MessageBuffer[14] >>4, MessageBuffer[15] & 0x0f, MessageBuffer[16] & 0x0f, MessageBuffer[16] >>4);
1312
1313   sprintf(NullNetworkInfo.CellID, "%02x%02x", MessageBuffer[10], MessageBuffer[11]);
1314
1315   sprintf(NullNetworkInfo.LAC, "%02x%02x", MessageBuffer[12], MessageBuffer[13]);
1316
1317 #ifdef DEBUG
1318   fprintf(stdout, _("   CellID: %s\n"), NullNetworkInfo.CellID);
1319   fprintf(stdout, _("   LAC: %s\n"), NullNetworkInfo.LAC);
1320   fprintf(stdout, _("   Network code: %s\n"), NullNetworkInfo.NetworkCode);
1321   fprintf(stdout, _("   Network name: %s (%s)\n"),
1322                      GSM_GetNetworkName(NullNetworkInfo.NetworkCode),
1323                      GSM_GetCountryName(NullNetworkInfo.NetworkCode));
1324   fprintf(stdout, _("   Status: "));
1325
1326   switch (MessageBuffer[8]) {
1327     case 0x01: fprintf(stdout, _("home network selected")); break;
1328     case 0x02: fprintf(stdout, _("roaming network")); break;
1329     case 0x03: fprintf(stdout, _("requesting network")); break;
1330     case 0x04: fprintf(stdout, _("not registered in the network")); break;
1331     default: fprintf(stdout, _("unknown"));
1332   }
1333
1334   fprintf(stdout, "\n");
1335
1336   fprintf(stdout, _("   Network selection: %s\n"), MessageBuffer[9]==1?_("manual"):_("automatic"));
1337 #endif /* DEBUG */
1338
1339   /* Make sure we are expecting NetworkInfo frame */
1340   if (CurrentNetworkInfo && CurrentNetworkInfoError == GE_BUSY)
1341     *CurrentNetworkInfo=NullNetworkInfo;
1342
1343   CurrentNetworkInfoError = GE_NONE;      
1344 }
1345
1346 GSM_Error N6110_GetNetworkInfo(GSM_NetworkInfo *NetworkInfo)
1347 {
1348   unsigned char req[] = { N6110_FRAME_HEADER,
1349                           0x70
1350                         };
1351
1352   GSM_Error error;
1353   
1354   CurrentNetworkInfo = NetworkInfo;
1355   
1356   error=NULL_SendMessageSequence
1357     (20, &CurrentNetworkInfoError, 4, 0x0a, req);
1358
1359   CurrentNetworkInfo = NULL;
1360
1361   return error;
1362 }
1363
1364 void N6110_ReplyGetProductProfileSetting(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1365
1366   int i;
1367   
1368 #ifdef DEBUG
1369   fprintf(stdout, _("Message: Product Profile Settings received -"));
1370   for (i=0;i<4;i++) fprintf(stdout, _(" %02x"),MessageBuffer[3+i]);
1371   fprintf(stdout, _("\n"));  
1372 #endif
1373
1374   for (i=0;i<4;i++) CurrentPPS[i]=MessageBuffer[3+i];
1375
1376   CurrentProductProfileSettingsError=GE_NONE;      
1377 }
1378
1379 GSM_Error N6110_GetProductProfileSetting (GSM_PPS *PPS)
1380 {
1381   unsigned char req[] = { 0x00, 0x01,0x6a };
1382   
1383   int i,j;
1384
1385   GSM_Error error;
1386
1387   error=N6110_EnableExtendedCommands(0x01);
1388   if (error!=GE_NONE) return error;
1389
1390   error=NULL_SendMessageSequence
1391     (20, &CurrentProductProfileSettingsError, 3, 0x40, req);
1392   if (error!=GE_NONE) return error;    
1393   
1394   switch (PPS->Name) {
1395     case PPS_ALS      : PPS->bool_value=(CurrentPPS[1]&32); break;
1396     case PPS_GamesMenu: PPS->bool_value=(CurrentPPS[3]&64); break;
1397     case PPS_HRData   : PPS->bool_value=(CurrentPPS[0]&64); break;
1398     case PPS_14400Data: PPS->bool_value=(CurrentPPS[0]&128);break;
1399     case PPS_EFR      : PPS->int_value =(CurrentPPS[0]&1)    +(CurrentPPS[0]&2);    break;
1400     case PPS_FR       : PPS->int_value =(CurrentPPS[0]&16)/16+(CurrentPPS[0]&32)/16;break;
1401     case PPS_HR       : PPS->int_value =(CurrentPPS[0]&4)/4  +(CurrentPPS[0]&8)/4;  break;
1402     case PPS_VibraMenu: PPS->bool_value=(CurrentPPS[4]&64); break;
1403     case PPS_LCDContrast:
1404          PPS->int_value=0;
1405          j=1;
1406          for (i=0;i<5;i++) {
1407            if (CurrentPPS[3]&j) PPS->int_value=PPS->int_value+j;
1408            j=j*2;
1409          }
1410          PPS->int_value=PPS->int_value*100/32;
1411          break;
1412
1413   }
1414   
1415   return (GE_NONE);
1416 }
1417
1418 void N6110_ReplySetProductProfileSetting(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1419
1420 #ifdef DEBUG
1421   int i;
1422   
1423   fprintf(stdout, _("Message: Product Profile Settings set to"));
1424   for (i=0;i<4;i++) fprintf(stdout, _(" %02x"),CurrentPPS[i]);
1425   fprintf(stdout, _("\n"));  
1426 #endif
1427      
1428   CurrentProductProfileSettingsError=GE_NONE;     
1429 }
1430
1431 GSM_Error N6110_SetProductProfileSetting (GSM_PPS *PPS)
1432 {
1433   unsigned char req[] = { 0x00, 0x01,0x6b, 
1434                           0x00, 0x00, 0x00, 0x00 }; /* bytes with Product Profile Setings */
1435   unsigned char settings[32];
1436   
1437   GSM_PPS OldPPS;
1438   
1439   int i,j,z;
1440   
1441   GSM_Error error;
1442
1443   error=N6110_EnableExtendedCommands(0x01);
1444   if (error!=GE_NONE) return error;
1445   
1446   OldPPS.Name=PPS_ALS;
1447   error=N6110_GetProductProfileSetting(&OldPPS);
1448   if (error!=GE_NONE) return error;
1449   
1450   j=128;z=0;
1451   for (i=0;i<32;i++) {
1452     if (CurrentPPS[z]&j)
1453       settings[i]='1';
1454     else
1455       settings[i]='0';    
1456     if (j==1) {
1457       j=128;
1458       z++;
1459     } else j=j/2;
1460   }
1461   
1462 #ifdef DEBUG
1463   fprintf(stdout,_("Current settings: "));
1464   for (i=0;i<32;i++) {
1465     fprintf(stdout,_("%c"),settings[i]);    
1466   }
1467   fprintf(stdout,_("\n"));
1468 #endif
1469
1470   switch (PPS->Name) {
1471     case PPS_ALS      :settings[10]=PPS->bool_value?'1':'0';break;
1472     case PPS_HRData   :settings[ 5]=PPS->bool_value?'1':'0';break;
1473     case PPS_14400Data:settings[ 6]=PPS->bool_value?'1':'0';break;
1474     default           :break;
1475   }
1476     
1477   j=128;z=0;
1478   for (i=0;i<32;i++) {
1479     if (settings[i]=='1') req[z+3]=req[z+3]+j;
1480     if (j==1) {
1481       j=128;
1482       z++;
1483     } else j=j/2;
1484   }  
1485
1486 #ifdef DEBUG
1487   fprintf(stdout,_("Current settings: "));
1488   for (i=0;i<4;i++) {
1489     fprintf(stdout,_("%i "),req[i+3]);    
1490   }
1491   fprintf(stdout,_("\n"));
1492 #endif
1493
1494   for (i=0;i<4;i++) {
1495    CurrentPPS[i]=req[i+3];    
1496   }
1497
1498   return NULL_SendMessageSequence
1499     (20, &CurrentProductProfileSettingsError, 7, 0x40, req);
1500 }
1501
1502 void N6110_ReplyPressKey(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1503
1504     if (MessageBuffer[4]==CurrentPressKeyEvent) CurrentPressKeyError=GE_NONE;
1505                                            else CurrentPressKeyError=GE_UNKNOWN; /* MessageBuffer[4] = 0x05 */
1506 #ifdef DEBUG
1507     fprintf(stdout, _("Message: Result of key "));
1508     switch (MessageBuffer[4])
1509     {
1510       case PRESSPHONEKEY:   fprintf(stdout, _("press OK\n"));break;
1511       case RELEASEPHONEKEY: fprintf(stdout, _("release OK\n"));break;
1512       default:              fprintf(stdout, _("press or release - error\n"));break;
1513     }
1514 #endif /* DEBUG */
1515 }
1516
1517 GSM_Error N6110_PressKey(int key, int event)
1518 {
1519   unsigned char req[] = {N6110_FRAME_HEADER, 0x42, 0x01, 0x00, 0x01};
1520   
1521   req[4]=event; /* if we press or release key */
1522   req[5]=key;
1523   
1524   CurrentPressKeyEvent=event;
1525   
1526   return NULL_SendMessageSequence
1527     (10, &CurrentPressKeyError, 7, 0x0c, req);
1528 }
1529
1530 void N6110_ReplyDisplayOutput(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1531
1532   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
1533   char model[64];
1534
1535   int i, j;
1536
1537   char uni[100];
1538     
1539   switch(MessageBuffer[3]) {
1540
1541   /* Phone sends displayed texts */
1542   case 0x50:
1543     NewX=MessageBuffer[6];
1544     NewY=MessageBuffer[5];
1545
1546     DecodeUnicode (uni, MessageBuffer+8, MessageBuffer[7]);
1547
1548 #ifdef DEBUG
1549     fprintf(stdout, _("New displayed text (%i %i): \"%s\"\n"),NewX,NewY,uni);      
1550 #endif /* DEBUG */
1551
1552     while (N6110_GetModel(model)  != GE_NONE)
1553       sleep(1);
1554
1555     /* With these rules it works almost excellent with my N5110 */
1556     /* I don't have general rule :-(, that's why you must experiment */
1557     /* with your phone. Nokia could make it better. MW */
1558     /* It's almost OK for N5110*/
1559     /* FIX ME: it will be the same for N5130 and 3210 too*/
1560     if (!strcmp(model,"NSE-1"))
1561     {
1562       /* OldX==1000 means - it's first time */
1563       if (OldX==1000) {
1564       
1565         /* Clean table */
1566         for (i=0;i<5+1;i++) {
1567           for (j=0;j<27+1;j++) {PhoneScreen[i][j]=' ';}
1568       }
1569       OldX=0;
1570     }
1571
1572     if ((OldX==0 && OldY==31 && NewX==29 && NewY==46) ||
1573         (OldX==0 && OldY==13 && NewX==23 && NewY==46)) {
1574       /* Clean the line with current text */
1575       for (j=0;j<27+1;j++) {PhoneScreen[NewY/(47/5)][j]=' ';}
1576       
1577       /* Inserts text into table */
1578       for (i=0; i<MessageBuffer[7];i++) {       
1579         PhoneScreen[NewY/(47/5)][NewX/(84/27)+i]=uni[i];
1580       }
1581
1582     }
1583
1584     if ((OldX==0 && OldY==21 && NewX==0 && NewY==10) ||
1585         (OldX==0 && OldY==10 && NewX==35 && NewY==46)) {
1586     } else {
1587       if ((OldX!=0 && NewX==0 && NewY!=6) ||
1588           (OldX==0 && NewX!=0 && OldY!=13 && OldY!=22) ||
1589           (OldX==0 && NewX==0 && NewY<OldY && (NewY!=13 || OldY!=26)) ||
1590           (OldY==5 && NewY!=5) ||
1591           (OldX==0 && OldY==13 && NewX==23 && NewY==46)) {
1592
1593         /* Writes "old" screen */
1594         for (i=0;i<5+1;i++) {
1595           for (j=0;j<27+1;j++) {fprintf(stdout,_("%c"),PhoneScreen[i][j]);}
1596             fprintf(stdout,_("\n"));
1597           }
1598         
1599           /* Clean table */
1600           for (i=0;i<5+1;i++) {
1601             for (j=0;j<27+1;j++) {PhoneScreen[i][j]=' ';}
1602           }
1603         }
1604       }
1605       
1606       /* Clean the line with current text */
1607       for (j=0;j<27+1;j++) {PhoneScreen[NewY/(47/5)][j]=' ';}
1608       
1609       /* Inserts text into table */
1610       for (i=0; i<MessageBuffer[7];i++) {       
1611         PhoneScreen[NewY/(47/5)][NewX/(84/27)+i]=uni[i];
1612       }
1613       
1614       OldY=NewY;
1615       OldX=NewX;
1616     } else {
1617 #ifndef DEBUG
1618       fprintf(stdout, _("%s\n"),uni);      
1619 #endif
1620     }
1621
1622     break;
1623  
1624   case 0x54:
1625       
1626     if (MessageBuffer[4]==1)
1627     {
1628       
1629 #ifdef DEBUG
1630       fprintf(stdout, _("Display output successfully disabled/enabled.\n"));
1631 #endif /* DEBUG */
1632
1633       CurrentDisplayOutputError=GE_NONE;
1634     }
1635        
1636     break;
1637   }
1638 }
1639
1640 GSM_Error SetDisplayOutput(unsigned char state)
1641 {
1642   unsigned char req[] = { N6110_FRAME_HEADER,
1643                           0x53, 0x00};
1644
1645   req[4]=state;
1646   
1647   return NULL_SendMessageSequence
1648     (30, &CurrentDisplayOutputError, 5, 0x0d, req);
1649 }
1650
1651 GSM_Error N6110_EnableDisplayOutput()
1652 {
1653   return SetDisplayOutput(0x01);
1654 }
1655  
1656 GSM_Error N6110_DisableDisplayOutput()
1657 {
1658   return SetDisplayOutput(0x02);
1659 }
1660
1661 /* If it is interesting for somebody: we can use 0x40 msg for it
1662    and it will work for all phones. See n6110.txt for details */
1663 GSM_Error N6110_AnswerCall(char s)
1664 {
1665         unsigned char req0[] = { N6110_FRAME_HEADER, 0x42,0x05,0x01,0x07,                                0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
1666                             0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80};
1667         unsigned char req[] = { N6110_FRAME_HEADER, 0x06, 0x00, 0x00};
1668
1669         req[4]=s;
1670
1671 #ifdef DEBUG
1672         fprintf(stdout,_("Answering call %d\n\r"),s);
1673 #endif
1674
1675         Protocol->SendMessage(sizeof(req0), 0x01, req0);
1676         sleep(1);
1677
1678         return NULL_SendMessageSequence
1679                 (20, &CurrentMagicError, sizeof(req) , 0x01, req);
1680 }
1681
1682 void N6110_ReplyGetProfile(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1683
1684   switch (MessageBuffer[3]) {
1685
1686   /* Profile feature */
1687   case 0x14:   
1688
1689     switch(GetModelFeature (FN_PROFILES)) {
1690       case F_PROF33:
1691         switch (MessageBuffer[6]) {
1692           case 0x00: CurrentProfile->KeypadTone  = MessageBuffer[8]; break;
1693           case 0x01: CurrentProfile->CallAlert   = MessageBuffer[8]; break;
1694           case 0x02: CurrentProfile->Ringtone    = MessageBuffer[8]; break;
1695           case 0x03: CurrentProfile->Volume      = MessageBuffer[8]; break;
1696           case 0x04: CurrentProfile->MessageTone = MessageBuffer[8]; break;
1697           case 0x05: CurrentProfile->Vibration   = MessageBuffer[8]; break;
1698           case 0x06: CurrentProfile->WarningTone = MessageBuffer[8]; break;
1699           case 0x07: CurrentProfile->ScreenSaver = MessageBuffer[8]; break;       
1700           default:
1701 #ifdef DEBUG
1702             fprintf(stdout,_("feature %i = value %i\n\n"),MessageBuffer[6],MessageBuffer[8]);
1703 #endif
1704             break;
1705         }
1706         break;
1707       default:
1708         switch (MessageBuffer[6]) {
1709           case 0x00: CurrentProfile->KeypadTone      = MessageBuffer[8];break;
1710           case 0x01: CurrentProfile->Lights          = MessageBuffer[8];break;
1711           case 0x02: CurrentProfile->CallAlert       = MessageBuffer[8];break;
1712           case 0x03: CurrentProfile->Ringtone        = MessageBuffer[8];break;
1713           case 0x04: CurrentProfile->Volume          = MessageBuffer[8];break;
1714           case 0x05: CurrentProfile->MessageTone     = MessageBuffer[8];break;
1715           case 0x06: CurrentProfile->Vibration       = MessageBuffer[8];break;
1716           case 0x07: CurrentProfile->WarningTone     = MessageBuffer[8];break;
1717           case 0x08: CurrentProfile->CallerGroups    = MessageBuffer[8];break;
1718           case 0x09: CurrentProfile->AutomaticAnswer = MessageBuffer[8];break;
1719           default:
1720 #ifdef DEBUG
1721             fprintf(stdout,_("feature %i = value %i\n\n"),MessageBuffer[6],MessageBuffer[8]);
1722 #endif
1723             break;
1724         }
1725         break;
1726     }
1727
1728     CurrentProfileError = GE_NONE;
1729     break;
1730
1731   /* Incoming profile name */
1732   case 0x1b:   
1733
1734     if (MessageBuffer[9] == 0x00) {
1735       CurrentProfile->DefaultName=MessageBuffer[8];
1736     } else {
1737       CurrentProfile->DefaultName=-1;      
1738         
1739       /* Here name is in Unicode */
1740       if (GetModelFeature (FN_PROFILES)==F_PROF33) {
1741         DecodeUnicode (CurrentProfile->Name, MessageBuffer+10, MessageBuffer[9]/2);
1742       } else {
1743         /* ...here not */
1744         sprintf(CurrentProfile->Name, MessageBuffer + 10, MessageBuffer[9]);
1745         CurrentProfile->Name[MessageBuffer[9]] = '\0';
1746       }
1747     }
1748
1749     CurrentProfileError = GE_NONE;
1750     break;
1751
1752   }
1753 }
1754
1755 /* Needs SIM card with PIN in phone */
1756 GSM_Error N6110_GetProfile(GSM_Profile *Profile)
1757 {
1758   int i;
1759   
1760   unsigned char name_req[] = { N6110_FRAME_HEADER, 0x1a, 0x00};
1761   unsigned char feat_req[] = { N6110_FRAME_HEADER, 0x13, 0x01, 0x00, 0x00};
1762
1763   GSM_Error error;
1764   
1765   CurrentProfile = Profile;
1766
1767   /* When after sending all frames feature==253, it means, that it is not
1768      supported */
1769   CurrentProfile->KeypadTone=253;
1770   CurrentProfile->Lights=253;    
1771   CurrentProfile->CallAlert=253; 
1772   CurrentProfile->Ringtone=253;  
1773   CurrentProfile->Volume=253;    
1774   CurrentProfile->MessageTone=253;
1775   CurrentProfile->WarningTone=253;
1776   CurrentProfile->Vibration=253;  
1777   CurrentProfile->CallerGroups=253;
1778   CurrentProfile->ScreenSaver=253; 
1779   CurrentProfile->AutomaticAnswer=253;
1780
1781   name_req[4] = Profile->Number;
1782
1783   error=NULL_SendMessageSequence
1784     (20, &CurrentProfileError, 5, 0x05, name_req);
1785   if (error!=GE_NONE) return error;
1786
1787   for (i = 0x00; i <= 0x09; i++) {
1788
1789     feat_req[5] = Profile->Number;
1790     
1791     feat_req[6] = i;
1792
1793     error=NULL_SendMessageSequence
1794       (20, &CurrentProfileError, 7, 0x05, feat_req);
1795     if (error!=GE_NONE) return error;
1796   }
1797
1798   if (Profile->DefaultName > -1)
1799   {
1800     switch(GetModelFeature (FN_PROFILES)) {
1801       case F_PROF33:
1802         switch (Profile->DefaultName) {
1803           case 0x00: sprintf(Profile->Name, "General");break;
1804           case 0x01: sprintf(Profile->Name, "Silent");break;
1805           case 0x02: sprintf(Profile->Name, "Descreet");break;
1806           case 0x03: sprintf(Profile->Name, "Loud");break;
1807           case 0x04: sprintf(Profile->Name, "My style");break;
1808           case 0x05: Profile->Name[0]=0;break;
1809           default  : sprintf(Profile->Name, "Unknown (%i)", Profile->DefaultName);break;
1810         }
1811         break;
1812       case F_PROF51:
1813         switch (Profile->DefaultName) {
1814           case 0x00: sprintf(Profile->Name, "Personal");break;
1815           case 0x01: sprintf(Profile->Name, "Car");break;
1816           case 0x02: sprintf(Profile->Name, "Headset");break;
1817           default  : sprintf(Profile->Name, "Unknown (%i)", Profile->DefaultName);break;
1818         }
1819         break;
1820       case F_PROF61:
1821         switch (Profile->DefaultName) {
1822           case 0x00: sprintf(Profile->Name, "General");break;
1823           case 0x01: sprintf(Profile->Name, "Silent");break;
1824           case 0x02: sprintf(Profile->Name, "Meeting");break;
1825           case 0x03: sprintf(Profile->Name, "Outdoor");break;
1826           case 0x04: sprintf(Profile->Name, "Pager");break;
1827           case 0x05: sprintf(Profile->Name, "Car");break;
1828           case 0x06: sprintf(Profile->Name, "Headset");break;
1829           default  : sprintf(Profile->Name, "Unknown (%i)", Profile->DefaultName);break;
1830         }
1831         break;
1832     }
1833   }
1834   
1835   return (GE_NONE);
1836
1837 }
1838
1839 void N6110_ReplySetProfile(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1840
1841   switch (MessageBuffer[3]) {
1842
1843   /* Profile feature change result */
1844   case 0x11:   
1845 #ifdef DEBUG
1846     fprintf(stdout, _("Message: Profile feature change result.\n"));
1847 #endif /* DEBUG */
1848     CurrentProfileError = GE_NONE;
1849     break;
1850
1851   /* Profile name set result */
1852   case 0x1d:   
1853 #ifdef DEBUG
1854     fprintf(stdout, _("Message: Profile name change result.\n"));
1855 #endif /* DEBUG */
1856     CurrentProfileError = GE_NONE;
1857     break;
1858
1859   }
1860 }
1861
1862 GSM_Error N6110_SetProfileFeature(u8 profile, u8 feature, u8 value)
1863 {
1864   unsigned char feat_req[] = { N6110_FRAME_HEADER, 0x10, 0x01,
1865                                0x00, 0x00, 0x00};
1866
1867   feat_req[5]=profile;
1868   feat_req[6]=feature;
1869   feat_req[7]=value;
1870
1871   return NULL_SendMessageSequence
1872     (20, &CurrentProfileError, 8, 0x05, feat_req);
1873 }
1874
1875 GSM_Error N6110_SetProfile(GSM_Profile *Profile)
1876 {
1877   int i,value;
1878
1879   unsigned char name_req[40] = { N6110_FRAME_HEADER, 0x1c, 0x01, 0x03,
1880                                  0x00, 0x00, 0x00};
1881
1882   GSM_Error error;
1883   
1884   name_req[7] = Profile->Number;
1885   name_req[8] = strlen(Profile->Name);
1886   name_req[6] = name_req[8] + 2;
1887
1888   for (i = 0; i < name_req[8]; i++)
1889     name_req[9 + i] = Profile->Name[i];
1890
1891   error=NULL_SendMessageSequence
1892     (20, &CurrentProfileError, name_req[8] + 9, 0x05, name_req);
1893   if (error!=GE_NONE) return error;
1894
1895   for (i = 0x00; i <= 0x09; i++) {
1896
1897     switch (i) {
1898       case 0x00: value = Profile->KeypadTone; break;
1899       case 0x01: value = Profile->Lights; break;
1900       case 0x02: value = Profile->CallAlert; break;
1901       case 0x03: value = Profile->Ringtone; break;
1902       case 0x04: value = Profile->Volume; break;
1903       case 0x05: value = Profile->MessageTone; break;
1904       case 0x06: value = Profile->Vibration; break;
1905       case 0x07: value = Profile->WarningTone; break;
1906       case 0x08: value = Profile->CallerGroups; break;
1907       case 0x09: value = Profile->AutomaticAnswer; break;
1908       default  : value = 0; break;
1909     }
1910
1911     error=N6110_SetProfileFeature(Profile->Number,i,value);
1912     if (error!=GE_NONE) return error;
1913   }
1914
1915   return (GE_NONE);
1916 }
1917
1918 #endif /* UCLINUX */
1919
1920 bool N6110_SendRLPFrame(RLP_F96Frame *frame, bool out_dtx)
1921 {
1922   u8 req[60] = { 0x00, 0xd9 };
1923                 
1924   /* Discontinuos transmission (DTX).  See section 5.6 of GSM 04.22 version
1925      7.0.1. */
1926        
1927   if (out_dtx)
1928     req[1]=0x01;
1929
1930   memcpy(req+2, (u8 *) frame, 32);
1931
1932   return (Protocol->SendFrame(32, 0xf0, req));
1933 }
1934
1935 #ifndef UCLINUX
1936
1937 void N6110_ReplyGetCalendarNote(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
1938
1939   int i, j;
1940
1941   u8 mychar1;
1942
1943   wchar_t wc;  
1944     
1945   switch (MessageBuffer[4]) {
1946
1947     case 0x01:
1948       
1949       CurrentCalendarNote->Type=MessageBuffer[8];
1950
1951       DecodeDateTime(MessageBuffer+9, &CurrentCalendarNote->Time);
1952
1953       DecodeDateTime(MessageBuffer+16, &CurrentCalendarNote->Alarm);
1954
1955       CurrentCalendarNote->Text[0]=0;
1956       
1957       if (GetModelFeature (FN_CALENDAR)==F_CAL33) {
1958         i=0;
1959         if (CurrentCalendarNote->Type == GCN_REMINDER) i=1; //first char is subset
1960         switch (MessageBuffer[24]) {
1961           case 3:
1962 #ifdef DEBUG
1963             fprintf(stdout,_("Subset 3 in reminder note !\n"));
1964 #endif
1965             while (i!=MessageBuffer[23]) {
1966               j=0;
1967               if (i!=MessageBuffer[23]-1) {
1968                 if (MessageBuffer[24+i]>=0xc2) {
1969                   DecodeWithUTF8Alphabet(MessageBuffer[24+i], MessageBuffer[24+i+1], &mychar1);
1970                   CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)+1]=0;
1971                   CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)]=mychar1;
1972                   j=-1;
1973                   i++;
1974                 }
1975               }
1976               if (j!=-1) {
1977                 CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)+1]=0;
1978                 CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)]=MessageBuffer[24+i];
1979               }
1980               i++;
1981             }
1982             break;
1983           case 2:
1984 #ifdef DEBUG
1985             fprintf(stdout,_("Subset 2 in reminder note !\n"));
1986 #endif
1987             while (i!=MessageBuffer[23]) {
1988               wc = MessageBuffer[24+i] | (0x00 << 8);
1989               CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)+1]=0;
1990               CurrentCalendarNote->Text[strlen(CurrentCalendarNote->Text)]=
1991                       DecodeWithUnicodeAlphabet(wc);
1992               i++;
1993             }
1994             break;
1995           case 1:
1996 #ifdef DEBUG
1997             fprintf(stdout,_("Subset 1 in reminder note !\n"));
1998 #endif
1999             memcpy(CurrentCalendarNote->Text,MessageBuffer+24+i,MessageBuffer[23]-i);
2000             CurrentCalendarNote->Text[MessageBuffer[23]-i]=0;
2001             break;
2002           default:
2003 #ifdef DEBUG
2004             fprintf(stdout,_("Unknown subset in reminder note !\n"));
2005 #endif
2006             memcpy(CurrentCalendarNote->Text,MessageBuffer+24+i,MessageBuffer[23]-i);
2007             CurrentCalendarNote->Text[MessageBuffer[23]-i]=0;
2008             break;
2009         }
2010       } else {
2011         memcpy(CurrentCalendarNote->Text,MessageBuffer+24,MessageBuffer[23]);
2012         CurrentCalendarNote->Text[MessageBuffer[23]]=0;
2013       }
2014       
2015       if (CurrentCalendarNote->Type == GCN_CALL) {
2016         memcpy(CurrentCalendarNote->Phone,MessageBuffer+24+MessageBuffer[23]+1,MessageBuffer[24+MessageBuffer[23]]);
2017         CurrentCalendarNote->Phone[MessageBuffer[24+MessageBuffer[23]]]=0;
2018       }
2019
2020       CurrentCalendarNote->Recurrance=0;
2021
2022       CurrentCalendarNote->AlarmType=0;
2023
2024 #ifdef DEBUG
2025       fprintf(stdout, _("Message: Calendar note received.\n"));
2026
2027       fprintf(stdout, _("   Date: %d-%02d-%02d\n"), CurrentCalendarNote->Time.Year,
2028                                            CurrentCalendarNote->Time.Month,
2029                                            CurrentCalendarNote->Time.Day);
2030
2031       fprintf(stdout, _("   Time: %02d:%02d:%02d\n"), CurrentCalendarNote->Time.Hour,
2032                                            CurrentCalendarNote->Time.Minute,
2033                                            CurrentCalendarNote->Time.Second);
2034
2035       /* Some messages do not have alarm set up */
2036       if (CurrentCalendarNote->Alarm.Year != 0) {
2037         fprintf(stdout, _("   Alarm date: %d-%02d-%02d\n"), CurrentCalendarNote->Alarm.Year,
2038                                                  CurrentCalendarNote->Alarm.Month,
2039                                                  CurrentCalendarNote->Alarm.Day);
2040
2041         fprintf(stdout, _("   Alarm time: %02d:%02d:%02d\n"), CurrentCalendarNote->Alarm.Hour,
2042                                                  CurrentCalendarNote->Alarm.Minute,
2043                                                  CurrentCalendarNote->Alarm.Second);
2044       }
2045
2046       fprintf(stdout, _("   Type: %d\n"), CurrentCalendarNote->Type);
2047       fprintf(stdout, _("   Text: %s\n"), CurrentCalendarNote->Text);
2048
2049       if (CurrentCalendarNote->Type == GCN_CALL)
2050         fprintf(stdout, _("   Phone: %s\n"), CurrentCalendarNote->Phone);
2051 #endif /* DEBUG */
2052
2053       CurrentCalendarNoteError=GE_NONE;
2054       break;
2055
2056     case 0x93:
2057
2058 #ifdef DEBUG
2059       fprintf(stdout, _("Message: Calendar note not available\n"));
2060 #endif /* DEBUG */
2061
2062       CurrentCalendarNoteError=GE_INVALIDCALNOTELOCATION;
2063       break;
2064
2065     default:
2066
2067 #ifdef DEBUG
2068       fprintf(stdout, _("Message: Calendar note error\n"));
2069 #endif /* DEBUG */
2070
2071       CurrentCalendarNoteError=GE_INTERNALERROR;
2072       break;
2073
2074   }
2075 }
2076
2077 GSM_Error N6110_GetCalendarNote(GSM_CalendarNote *CalendarNote)
2078 {
2079
2080   unsigned char req[] = { N6110_FRAME_HEADER,
2081                           0x66, 0x00
2082                         };
2083   GSM_Error error;
2084
2085   req[4]=CalendarNote->Location;
2086
2087   CurrentCalendarNote = CalendarNote;
2088
2089   error=NULL_SendMessageSequence
2090     (20, &CurrentCalendarNoteError, 5, 0x13, req);
2091
2092   CurrentCalendarNote = NULL;
2093
2094   return error;
2095 }
2096
2097 void N6110_ReplyWriteCalendarNote(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2098
2099 #ifdef DEBUG
2100   switch(MessageBuffer[4]) {
2101     /* This message is also sent when the user enters the new entry on keypad */
2102     case 0x01:
2103       fprintf(stdout, _("Message: Calendar note write succesfull!\n"));break;      
2104     case 0x73:
2105       fprintf(stdout, _("Message: Calendar note write failed!\n"));break;
2106     case 0x7d:
2107       fprintf(stdout, _("Message: Calendar note write failed!\n"));break;
2108     default:
2109       fprintf(stdout, _("Unknown message of type 0x13 and subtype 0x65\n"));break;
2110   }
2111 #endif
2112
2113   switch(MessageBuffer[4]) {
2114     case 0x01: CurrentCalendarNoteError=GE_NONE; break;      
2115     case 0x73: CurrentCalendarNoteError=GE_INTERNALERROR; break;
2116     case 0x7d: CurrentCalendarNoteError=GE_INTERNALERROR; break;
2117     default  : AppendLogText("Unknown msg\n",false); break;
2118   }
2119 }
2120
2121 GSM_Error N6110_WriteCalendarNote(GSM_CalendarNote *CalendarNote)
2122 {
2123
2124   unsigned char req[200] = { N6110_FRAME_HEADER,
2125                              0x64, 0x01, 0x10,
2126                              0x00, /* Length of the rest of the frame. */
2127                              0x00, /* The type of calendar note */
2128                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2129                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2130                         };
2131
2132   typedef struct {
2133     char *model;
2134     unsigned char call;
2135     unsigned char meeting;
2136     unsigned char birthday;
2137     unsigned char reminder;
2138   } calendar_model_length;
2139   
2140   /* Length of entries */
2141   calendar_model_length calendar_lengths[] =
2142   {
2143     /*model,CallTo,Meeting,Birthday,Reminder*/
2144     {"NHM-5",0x24,0x24,0x24,0x24}, //Reminder from phone, other quesses
2145     {"NHM-6",0x24,0x24,0x24,0x24}, //Reminder from phone, other quesses
2146     {"NSE-3",0x1e,0x14,0x14,0x1e}, //from NCDS3 [HKEY_LOCAL_MACHINE\Software\Nokia\Data Suite\3.0\Calendar]
2147     {"NSM-1",0x1e,0x18,0x18,0x24}, //from NCDS3 
2148     {"NSK-3",0x1e,0x14,0x14,0x1e}, //from NCDS3 
2149     {"NSB-3",0x20,0x14,0x14,0x1e}, //from NCDS3
2150     {"",     0,   0,   0,   0   }  //end of table
2151   };
2152
2153   int i, j, current;
2154
2155   u8 mychar;
2156   
2157   u8 mychar1,mychar2;
2158   
2159   GSM_Error error;
2160   
2161   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
2162   char model[64];
2163
2164   req[7]=CalendarNote->Type;
2165
2166   EncodeDateTime(req+8, &CalendarNote->Time);
2167   req[14] = CalendarNote->Time.Timezone;
2168
2169   if (CalendarNote->Alarm.Year) {
2170     EncodeDateTime(req+15, &CalendarNote->Alarm);
2171     req[21] = CalendarNote->Alarm.Timezone;
2172   }
2173
2174   req[22]=strlen(CalendarNote->Text);
2175   
2176   current=23;
2177
2178   if (GetModelFeature (FN_CALENDAR)==F_CAL33 && CalendarNote->Type==GCN_REMINDER) {
2179     req[22]++;           // one additional char
2180     req[current++]=0x01; //we use now subset 1
2181   }
2182     
2183   for (i=0; i<strlen(CalendarNote->Text); i++) {
2184     j=0;
2185     mychar=CalendarNote->Text[i];
2186     if (GetModelFeature (FN_CALENDAR)==F_CAL33 && CalendarNote->Type==GCN_REMINDER) {
2187       if (EncodeWithUTF8Alphabet(mychar,&mychar1,&mychar2)) {
2188           req[current++]=mychar1;
2189           req[current++]=mychar2;
2190           req[23]=0x03; //use subset 3
2191           req[22]++;    // one additional char
2192           j=-1;
2193       }
2194     }
2195     if (j!=-1) {
2196       /* Enables/disables blinking */
2197       if (mychar=='~') req[current++]=0x01;
2198                   else req[current++]=mychar;
2199     }
2200   }
2201
2202   req[current++]=strlen(CalendarNote->Phone);
2203
2204   for (i=0; i<strlen(CalendarNote->Phone); i++)
2205     req[current++]=CalendarNote->Phone[i];
2206
2207   while (N6110_GetModel(model)  != GE_NONE)
2208     sleep(1);
2209
2210   /* Checking maximal length */
2211   i=0;
2212   while (strcmp(calendar_lengths[i].model,"")) {
2213     if (!strcmp(calendar_lengths[i].model,model)) {
2214       switch (CalendarNote->Type) {
2215         case GCN_REMINDER:if (req[22]>calendar_lengths[i].reminder) return GE_TOOLONG;break;
2216         case GCN_MEETING :if (req[22]>calendar_lengths[i].meeting)  return GE_TOOLONG;break;
2217         case GCN_BIRTHDAY:if (req[22]>calendar_lengths[i].birthday) return GE_TOOLONG;break;
2218         case GCN_CALL    :if (strlen(CalendarNote->Phone)>calendar_lengths[i].call) return GE_TOOLONG;break;
2219       }
2220       break;
2221     }
2222     i++;
2223   }
2224
2225   CurrentCalendarNote = CalendarNote;
2226
2227   error=NULL_SendMessageSequence
2228     (20, &CurrentCalendarNoteError, current, 0x13, req);
2229
2230   CurrentCalendarNote = NULL;
2231
2232   return error;
2233 }
2234
2235 void N6110_ReplyDeleteCalendarNote(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2236
2237 #ifdef DEBUG
2238   switch (MessageBuffer[4]) {
2239     /* This message is also sent when the user deletes an old entry on
2240        keypad or moves an old entry somewhere (there is also `write'
2241        message). */
2242     case 0x01:fprintf(stdout, _("Message: Calendar note deleted\n"));break;
2243     case 0x93:fprintf(stdout, _("Message: Calendar note can't be deleted\n"));break;
2244     default  :fprintf(stdout, _("Message: Calendar note deleting error\n"));break;
2245   }
2246 #endif
2247
2248   switch (MessageBuffer[4]) {
2249     case 0x01:CurrentCalendarNoteError=GE_NONE;break;
2250     case 0x93:CurrentCalendarNoteError=GE_INVALIDCALNOTELOCATION;break;
2251     default  :CurrentCalendarNoteError=GE_INTERNALERROR;break;
2252   }
2253 }
2254
2255 GSM_Error N6110_DeleteCalendarNote(GSM_CalendarNote *CalendarNote)
2256 {
2257
2258   unsigned char req[] = { N6110_FRAME_HEADER,
2259                           0x68, 0x00
2260                         };
2261
2262   req[4]=CalendarNote->Location;
2263
2264   return NULL_SendMessageSequence (20, &CurrentCalendarNoteError, 5, 0x13, req);
2265 }
2266
2267 #endif /* UCLINUX */
2268
2269 static void N6110_ReplyRFBatteryLevel(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2270
2271 #ifdef DEBUG
2272     fprintf(stdout, _("Message: Phone status received:\n"));
2273     fprintf(stdout, _("   Mode: "));
2274
2275     switch (MessageBuffer[4]) {
2276
2277       case 0x01:
2278
2279         fprintf(stdout, _("registered within the network\n"));
2280         break;
2281               
2282       /* I was really amazing why is there a hole in the type of 0x02, now I
2283          know... */
2284       case 0x02: fprintf(stdout, _("call in progress\n"));          break; /* ringing or already answered call */
2285       case 0x03: fprintf(stdout, _("waiting for security code\n")); break;
2286       case 0x04: fprintf(stdout, _("powered off\n"));               break;
2287       default  : fprintf(stdout, _("unknown\n"));
2288
2289     }
2290
2291     fprintf(stdout, _("   Power source: "));
2292
2293     switch (MessageBuffer[7]) {
2294
2295       case 0x01: fprintf(stdout, _("AC/DC\n"));   break;
2296       case 0x02: fprintf(stdout, _("battery\n")); break;
2297       default  : fprintf(stdout, _("unknown\n"));
2298
2299     }
2300
2301     fprintf(stdout, _("   Battery Level: %d\n"), MessageBuffer[8]);
2302     fprintf(stdout, _("   Signal strength: %d\n"), MessageBuffer[5]);
2303 #endif /* DEBUG */
2304
2305     CurrentRFLevel=MessageBuffer[5];
2306     CurrentBatteryLevel=MessageBuffer[8];
2307     CurrentPowerSource=MessageBuffer[7];
2308 }
2309
2310
2311 GSM_Error N6110_GetRFLevel(GSM_RFUnits *units, float *level)
2312 {
2313
2314   /* FIXME - these values are from 3810 code, may be incorrect.  Map from
2315      values returned in status packet to the the values returned by the AT+CSQ
2316      command. */
2317   float csq_map[5] = {0, 8, 16, 24, 31};
2318
2319   int timeout=10;
2320   int rf_level;
2321   
2322   char screen[NM_MAX_SCREEN_WIDTH];
2323
2324   CurrentRFLevel=-1;
2325     
2326   if (GetModelFeature (FN_NOPOWERFRAME)==F_NOPOWER) {
2327
2328 #ifndef UCLINUX
2329     if (N6110_NetMonitor(1, screen)!=GE_NONE)
2330       return GE_INTERNALERROR;
2331 #endif /* UCLINUX */
2332     
2333     rf_level=4;
2334     
2335     if (screen[4]!='-') {
2336       if (screen[5]=='9' && screen[6]>'4') rf_level=1;
2337       if (screen[5]=='9' && screen[6]<'5') rf_level=2;
2338       if (screen[5]=='8' && screen[6]>'4') rf_level=3;      
2339     } else rf_level=0;
2340
2341     /* Arbitrary units. */
2342     if (*units == GRF_Arbitrary) {
2343       *level = rf_level;
2344       return (GE_NONE);
2345     }
2346     
2347   } else {
2348     N6110_SendStatusRequest();
2349
2350     /* Wait for timeout or other error. */
2351     while (timeout != 0 && CurrentRFLevel == -1 ) {
2352
2353       if (--timeout == 0)
2354         return (GE_TIMEOUT);
2355
2356       usleep (100000);
2357     }
2358
2359     /* Make copy in case it changes. */
2360     rf_level = CurrentRFLevel;
2361
2362     if (rf_level == -1)
2363       return (GE_NOLINK);
2364
2365     /* Now convert between the different units we support. */
2366
2367     /* Arbitrary units. */
2368     if (*units == GRF_Arbitrary) {
2369       *level = rf_level;
2370       return (GE_NONE);
2371     }
2372
2373     /* CSQ units. */
2374     if (*units == GRF_CSQ) {
2375
2376       if (rf_level <=4)
2377         *level = csq_map[rf_level];
2378       else
2379         *level = 99; /* Unknown/undefined */
2380
2381       return (GE_NONE);
2382     }
2383   }
2384
2385   /* Unit type is one we don't handle so return error */
2386   return (GE_INTERNALERROR);
2387 }
2388
2389
2390 GSM_Error N6110_GetBatteryLevel(GSM_BatteryUnits *units, float *level)
2391 {
2392   int timeout=10;
2393   int batt_level;
2394
2395   char screen[NM_MAX_SCREEN_WIDTH];
2396
2397   CurrentBatteryLevel=-1;
2398
2399   if (GetModelFeature (FN_NOPOWERFRAME)==F_NOPOWER) {
2400
2401 #ifndef UCLINUX
2402     if (N6110_NetMonitor(23, screen)!=GE_NONE)
2403       return GE_NOLINK;
2404 #endif /* UCLINUX */
2405     
2406     batt_level=4;
2407     
2408     if (screen[29]=='7') batt_level=3;
2409     if (screen[29]=='5') batt_level=2;
2410     if (screen[29]=='2') batt_level=1;
2411     
2412     /* Only units we handle at present are GBU_Arbitrary */
2413     if (*units == GBU_Arbitrary) {
2414       *level = batt_level;
2415       return (GE_NONE);
2416     }
2417
2418     return (GE_INTERNALERROR);    
2419     
2420   } else {
2421     N6110_SendStatusRequest();
2422
2423     /* Wait for timeout or other error. */
2424     while (timeout != 0 && CurrentBatteryLevel == -1 ) {
2425
2426       if (--timeout == 0)
2427         return (GE_TIMEOUT);
2428
2429       usleep (100000);
2430     }
2431
2432     /* Take copy in case it changes. */
2433     batt_level = CurrentBatteryLevel;
2434
2435     if (batt_level != -1) {
2436
2437       /* Only units we handle at present are GBU_Arbitrary */
2438       if (*units == GBU_Arbitrary) {
2439         *level = batt_level;
2440         return (GE_NONE);
2441       }
2442
2443       return (GE_INTERNALERROR);
2444     }
2445     else
2446       return (GE_NOLINK);
2447   }
2448 }
2449
2450 GSM_Error N6110_GetPowerSource(GSM_PowerSource *source)
2451 {
2452
2453   int timeout=10;
2454
2455   char screen[NM_MAX_SCREEN_WIDTH];
2456
2457   CurrentPowerSource=-1;
2458
2459   if (GetModelFeature (FN_NOPOWERFRAME)==F_NOPOWER) {    
2460
2461 #ifndef UCLINUX
2462     if (N6110_NetMonitor(20, screen)!=GE_NONE)
2463       return GE_NOLINK;
2464 #endif /* UCLINUX */
2465     
2466     CurrentPowerSource=GPS_ACDC;
2467
2468     if (screen[6]=='x') CurrentPowerSource=GPS_BATTERY;
2469
2470     *source=CurrentPowerSource;        
2471     
2472     return GE_NONE;    
2473   } else {
2474     N6110_SendStatusRequest();
2475
2476     /* Wait for timeout or other error. */
2477     while (timeout != 0 && CurrentPowerSource == -1 ) {
2478
2479       if (--timeout == 0)
2480         return (GE_TIMEOUT);
2481
2482       usleep (100000);
2483     }
2484
2485     if (CurrentPowerSource != -1) {
2486       *source=CurrentPowerSource;
2487       return (GE_NONE);
2488     }
2489     else
2490       return (GE_NOLINK);
2491   }
2492 }
2493
2494 #ifndef UCLINUX
2495
2496 static void N6110_ReplyGetDisplayStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2497
2498   int i;
2499
2500   for (i=0; i<MessageBuffer[4];i++)
2501     if (MessageBuffer[2*i+6]==2)
2502       CurrentDisplayStatus|=1<<(MessageBuffer[2*i+5]-1);
2503     else
2504       CurrentDisplayStatus&= (0xff - (1<<(MessageBuffer[2*i+5]-1)));
2505
2506 #ifdef DEBUG
2507   fprintf(stdout, _("Call in progress: %s\n"), CurrentDisplayStatus & (1<<DS_Call_In_Progress)?"on":"off");
2508   fprintf(stdout, _("Unknown: %s\n"),          CurrentDisplayStatus & (1<<DS_Unknown)?"on":"off");
2509   fprintf(stdout, _("Unread SMS: %s\n"),       CurrentDisplayStatus & (1<<DS_Unread_SMS)?"on":"off");
2510   fprintf(stdout, _("Voice call: %s\n"),       CurrentDisplayStatus & (1<<DS_Voice_Call)?"on":"off");
2511   fprintf(stdout, _("Fax call active: %s\n"),  CurrentDisplayStatus & (1<<DS_Fax_Call)?"on":"off");
2512   fprintf(stdout, _("Data call active: %s\n"), CurrentDisplayStatus & (1<<DS_Data_Call)?"on":"off");
2513   fprintf(stdout, _("Keyboard lock: %s\n"),    CurrentDisplayStatus & (1<<DS_Keyboard_Lock)?"on":"off");
2514   fprintf(stdout, _("SMS storage full: %s\n"), CurrentDisplayStatus & (1<<DS_SMS_Storage_Full)?"on":"off");
2515 #endif /* DEBUG */
2516
2517   CurrentDisplayStatusError=GE_NONE;
2518 }
2519
2520 GSM_Error N6110_GetDisplayStatus(int *Status) {
2521
2522   unsigned char req[4]={ N6110_FRAME_HEADER, 0x51 };
2523
2524   GSM_Error error;
2525
2526   error=NULL_SendMessageSequence
2527     (10, &CurrentDisplayStatusError, 4, 0x0d, req);
2528   if (error!=GE_NONE) return error;
2529   
2530   *Status=CurrentDisplayStatus;
2531
2532   return GE_NONE;
2533 }
2534
2535 GSM_Error N6110_DialVoice(char *Number) {
2536 /* This commented sequence doesn't work on N3210/3310/6210/7110 */
2537 //  unsigned char req[64]={N6110_FRAME_HEADER, 0x01};
2538 //  unsigned char req_end[]={0x05, 0x01, 0x01, 0x05, 0x81, 0x01, 0x00, 0x00, 0x01};
2539 //  int i=0;
2540 //  req[4]=strlen(Number);
2541 //  for(i=0; i < strlen(Number) ; i++)
2542 //   req[5+i]=Number[i];
2543 //  memcpy(req+5+strlen(Number), req_end, 10);
2544 //  return NULL_SendMessageSequence
2545 //    (20, &CurrentDialVoiceError, 13+strlen(Number), 0x01, req);
2546
2547   unsigned char req[64]={0x00,0x01,0x7c,
2548                          0x01}; //call command
2549
2550   int i=0;                       
2551   
2552   GSM_Error error;
2553
2554   error=N6110_EnableExtendedCommands(0x01);
2555   if (error!=GE_NONE) return error;
2556
2557   for(i=0; i < strlen(Number) ; i++) req[4+i]=Number[i];
2558   
2559   req[4+i+1]=0;
2560   
2561   return NULL_SendMessageSequence
2562     (20, &CurrentDialVoiceError, 4+strlen(Number)+1, 0x40, req);  
2563 }
2564
2565 #endif /* UCLINUX */
2566
2567 /* Dial a data call - type specifies request to use: 
2568      type 0 should normally be used
2569      type 1 should be used when calling a digital line - corresponds to ats35=0
2570      Maybe one day we'll know what they mean!
2571 */
2572 GSM_Error N6110_DialData(char *Number, char type, void (* callpassup)(char c))
2573 {
2574         unsigned char req[100]   = { N6110_FRAME_HEADER, 0x01 };
2575         unsigned char *req_end;
2576         unsigned char req_end0[] = { 0x01,  /* make a data call = type 0x01 */
2577                                      0x02,0x01,0x05,0x81,0x01,0x00,0x00,0x01,0x02,0x0a,
2578                                      0x07,0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00 };
2579         unsigned char req_end1[] = { 0x01,
2580                                      0x02,0x01,0x05,0x81,0x01,0x00,0x00,0x01,0x02,0x0a,
2581                                      0x07,0xa1,0x88,0x89,0x21,0x15,0x63,0xa0,0x00,0x06,
2582                                      0x88,0x90,0x21,0x48,0x40,0xbb };
2583         unsigned char req2[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x01,
2584                                      0x07,0xa2,0xc8,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
2585                                      0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80,0x01,0x60 };
2586         unsigned char req3[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x01,
2587                                      0x07,0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
2588                                      0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80 };
2589         unsigned char req4[]     = { N6110_FRAME_HEADER, 0x42,0x05,0x81,
2590                                      0x07,0xa1,0x88,0x89,0x21,0x15,0x63,0xa0,0x00,0x06,
2591                                      0x88,0x90,0x21,0x48,0x40,0xbb,0x07,0xa3,0xb8,0x81,
2592                                      0x20,0x15,0x63,0x80 };
2593
2594         int i = 0;
2595         u8 size;
2596
2597         CurrentCallPassup=callpassup;
2598
2599         switch (type) {
2600         case 0:
2601                 usleep(100); Protocol->SendMessage(sizeof(req3), 0x01, req3);   /* Lace */
2602                 usleep(100);
2603                 req_end = req_end0;
2604                 size = sizeof(req_end0);
2605                 break;
2606         case 1:
2607                 Protocol->SendMessage(sizeof(req3), 0x01, req3);
2608                 usleep(1000000);
2609                 Protocol->SendMessage(sizeof(req4), 0x01, req4);
2610                 usleep(1000000);
2611                 req_end = req_end1;
2612                 size = sizeof(req_end1);
2613                 break;
2614         case -1:   /* Just used to set the call passup */
2615                 return GE_NONE;
2616                 break;
2617         default:
2618                 req_end = req_end0;
2619                 size = sizeof(req_end0);
2620                 break;
2621         }
2622
2623         req[4] = strlen(Number);
2624
2625         for(i = 0; i < strlen(Number) ; i++)
2626                 req[5+i] = Number[i];
2627
2628         memcpy(req + 5 + strlen(Number), req_end, size);
2629
2630         Protocol->SendMessage(5 + size + strlen(Number), 0x01, req);
2631         usleep(1000000);
2632
2633 #if 0
2634         if (type != 1) Protocol->SendMessage(26, 0x01, req2);
2635 #endif
2636
2637         return (GE_NONE);
2638 }
2639
2640 #ifndef UCLINUX
2641
2642 GSM_Error N6110_GetIncomingCallNr(char *Number)
2643 {
2644
2645   if (*CurrentIncomingCall != ' ') {
2646     strcpy(Number, CurrentIncomingCall);
2647     return GE_NONE;
2648   }
2649   else
2650     return GE_BUSY;
2651 }
2652
2653 #endif /* UCLINUX */
2654
2655 GSM_Error N6110_CancelCall(void)
2656 {
2657 //  This frame & method works only on 61xx/51xx
2658 //  unsigned char req[] = { N6110_FRAME_HEADER, 0x08, 0x00, 0x85};
2659 //  req[4]=CurrentCallSequenceNumber;
2660 //  Protocol->SendMessage(6, 0x01, req);
2661 //  return GE_NONE;
2662  
2663   GSM_Error error;
2664
2665   unsigned char req[]={0x00,0x01,0x7c,0x03};
2666     
2667   /* Checking */
2668   error=N6110_EnableExtendedCommands(0x01);
2669   if (error!=GE_NONE) return error;
2670
2671   return NULL_SendMessageSequence (20, &CurrentDialVoiceError, 4, 0x40, req);   
2672 }  
2673
2674 #ifndef UCLINUX
2675
2676 void N6110_ReplyEnterSecurityCode(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2677     
2678   switch(MessageBuffer[3]) {
2679
2680   case 0x0b:
2681 #ifdef DEBUG
2682     fprintf(stdout, _("Message: Security code accepted.\n"));
2683 #endif /* DEBUG */
2684     CurrentSecurityCodeError = GE_NONE;
2685     break;
2686
2687   default:
2688 #ifdef DEBUG
2689     fprintf(stdout, _("Message: Security code is wrong. You're not my big owner :-)\n"));
2690 #endif /* DEBUG */
2691     CurrentSecurityCodeError = GE_INVALIDSECURITYCODE;
2692   }
2693 }
2694
2695 GSM_Error N6110_EnterSecurityCode(GSM_SecurityCode SecurityCode)
2696 {
2697
2698   unsigned char req[15] = { N6110_FRAME_HEADER,
2699                             0x0a, /* Enter code request. */
2700                             0x00  /* Type of the entered code. */
2701                             };
2702   int i=0;
2703
2704   req[4]=SecurityCode.Type;
2705
2706   for (i=0; i<strlen(SecurityCode.Code);i++)
2707     req[5+i]=SecurityCode.Code[i];
2708
2709   req[5+strlen(SecurityCode.Code)]=0x00;
2710   req[6+strlen(SecurityCode.Code)]=0x00;
2711
2712   return NULL_SendMessageSequence
2713     (20, &CurrentSecurityCodeError, 7+strlen(SecurityCode.Code), 0x08, req);
2714 }
2715
2716 void N6110_ReplyGetSecurityCodeStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2717     
2718   *CurrentSecurityCodeStatus = MessageBuffer[4];
2719
2720 #ifdef DEBUG
2721   fprintf(stdout, _("Message: Security Code status received: "));
2722
2723   switch(*CurrentSecurityCodeStatus) {
2724
2725     case GSCT_SecurityCode: fprintf(stdout, _("waiting for Security Code.\n")); break;
2726     case GSCT_Pin         : fprintf(stdout, _("waiting for PIN.\n")); break;
2727     case GSCT_Pin2        : fprintf(stdout, _("waiting for PIN2.\n")); break;
2728     case GSCT_Puk         : fprintf(stdout, _("waiting for PUK.\n")); break;
2729     case GSCT_Puk2        : fprintf(stdout, _("waiting for PUK2.\n")); break;
2730     case GSCT_None        : fprintf(stdout, _("nothing to enter.\n")); break;
2731     default               : fprintf(stdout, _("Unknown!\n"));
2732   }
2733       
2734 #endif /* DEBUG */
2735
2736   CurrentSecurityCodeError = GE_NONE;
2737 }
2738
2739 GSM_Error N6110_GetSecurityCodeStatus(int *Status)
2740 {
2741
2742   unsigned char req[4] = { N6110_FRAME_HEADER,
2743                            0x07
2744                          };
2745
2746   CurrentSecurityCodeStatus=Status;
2747
2748   return NULL_SendMessageSequence
2749     (20, &CurrentSecurityCodeError, 4, 0x08, req);
2750 }
2751
2752 void N6110_ReplyGetSecurityCode(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2753
2754   int i;
2755   
2756 #ifdef DEBUG
2757   fprintf(stdout, _("Message: Security code received: "));
2758   switch (MessageBuffer[3]) {
2759     case GSCT_SecurityCode: fprintf(stdout, _("Security code"));break;
2760     case GSCT_Pin:  fprintf(stdout, _("PIN"));break;
2761     case GSCT_Pin2: fprintf(stdout, _("PIN2"));break;
2762     case GSCT_Puk:  fprintf(stdout, _("PUK"));break;
2763     case GSCT_Puk2: fprintf(stdout, _("PUK2"));break;
2764     default: fprintf(stdout, _("unknown !"));break;
2765   }
2766   if (MessageBuffer[4]==1) {
2767     fprintf(stdout, _(" allowed, value \""));
2768     if (MessageBuffer[3]==GSCT_SecurityCode) {
2769       for (i=0;i<5;i++) {fprintf(stdout, _("%c"), MessageBuffer[5+i]);}
2770     }
2771     if (MessageBuffer[3]==GSCT_Pin || MessageBuffer[3]==GSCT_Pin2 ||
2772         MessageBuffer[3]==GSCT_Puk || MessageBuffer[3]==GSCT_Puk2) {
2773       for (i=0;i<4;i++) {fprintf(stdout, _("%c"), MessageBuffer[5+i]);}
2774     }
2775     fprintf(stdout, _("\""));
2776   } else {
2777     fprintf(stdout, _(" not allowed"));  
2778   }
2779   fprintf(stdout, _("\n"));  
2780 #endif /* DEBUG */
2781       
2782   if (CurrentSecurityCode->Type==MessageBuffer[3] /* We wanted this code */
2783           && MessageBuffer[4]==1) {                      /* It's allowed */
2784     if (MessageBuffer[3]==GSCT_SecurityCode) {
2785       for (i=0;i<5;i++) {CurrentSecurityCode->Code[i]=MessageBuffer[5+i];}
2786       CurrentSecurityCode->Code[5]=0;
2787     }
2788     if (MessageBuffer[3]==GSCT_Pin || MessageBuffer[3]==GSCT_Pin2 ||
2789         MessageBuffer[3]==GSCT_Puk || MessageBuffer[3]==GSCT_Puk2) {
2790       for (i=0;i<4;i++) {CurrentSecurityCode->Code[i]=MessageBuffer[5+i];}
2791       CurrentSecurityCode->Code[4]=0;
2792     }
2793     CurrentSecurityCodeError=GE_NONE;
2794   } else
2795     CurrentSecurityCodeError=GE_INVALIDSECURITYCODE;
2796 }
2797
2798 GSM_Error N6110_GetSecurityCode(GSM_SecurityCode *SecurityCode)
2799 {
2800
2801   unsigned char req[4] = { 0x00,
2802                            0x01,0x6e, /* Get code request. */
2803                            0x00 };    /* Type of the requested code. */
2804
2805   GSM_Error error;
2806   
2807   error=N6110_EnableExtendedCommands(0x01);
2808   if (error!=GE_NONE) return error;
2809   
2810   req[3]=SecurityCode->Type;
2811
2812   CurrentSecurityCode=SecurityCode;
2813
2814   return NULL_SendMessageSequence
2815     (20, &CurrentSecurityCodeError, 4, 0x40, req);
2816 }
2817
2818 void N6110_ReplyPlayTone(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2819
2820 #ifdef DEBUG
2821   fprintf(stdout, _("Message: answer for PlayTone frame\n"));      
2822 #endif
2823       
2824   CurrentPlayToneError=GE_NONE;      
2825 }
2826
2827 GSM_Error N6110_PlayTone(int Herz, u8 Volume)
2828 {
2829   unsigned char req[6] = { 0x00,0x01,0x8f,
2830                            0x00,   /* Volume */
2831                            0x00,   /* HerzLo */
2832                            0x00 }; /* HerzHi */
2833
2834   GSM_Error error;
2835
2836   /* PlayTone wasn't used earlier */
2837   if (CurrentPlayToneError==GE_UNKNOWN) {
2838     if (CurrentConnectionType!=GCT_MBUS)
2839       CurrentDisableKeepAlive=true;
2840
2841     error=N6110_EnableExtendedCommands(0x01);
2842     if (error!=GE_NONE) return error;
2843   }
2844
2845   /* For Herz==255*255 we have silent */  
2846   if (Herz!=255*255) {
2847     req[3]=Volume;
2848
2849     req[5]=Herz%256;
2850     req[4]=Herz/256;
2851   } else {
2852     req[3]=0;
2853
2854     req[5]=0;
2855     req[4]=0;
2856   }
2857
2858 #ifdef WIN32
2859   /* For Herz==255*255 we have silent and additionaly
2860      we wait for phone answer - it's important for MBUS */
2861   if (Herz==255*255) {
2862     error=NULL_SendMessageSequence
2863       (20, &CurrentPlayToneError, 6, 0x40, req);
2864
2865     CurrentPlayToneError=GE_UNKNOWN;
2866     CurrentDisableKeepAlive=false;
2867
2868     if (error!=GE_NONE) return error;
2869   } else {
2870     Protocol->SendMessage(6,0x40,req);
2871   }
2872 #else
2873   error=NULL_SendMessageSequence
2874     (20, &CurrentPlayToneError, 6, 0x40, req);
2875
2876   /* For Herz==255*255 we wait for phone answer - it's important for MBUS */
2877   if (Herz==255*255) {
2878     CurrentPlayToneError=GE_UNKNOWN;
2879     CurrentDisableKeepAlive=false;
2880   }
2881   
2882   if (error!=GE_NONE) return error;
2883
2884 #endif
2885     
2886   return(GE_NONE);
2887 }
2888
2889 void N6110_ReplyGetDateTime(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2890
2891   if (MessageBuffer[4]==0x01) {
2892     DecodeDateTime(MessageBuffer+8, CurrentDateTime);
2893
2894 #ifdef DEBUG
2895     fprintf(stdout, _("Message: Date and time\n"));
2896     fprintf(stdout, _("   Time: %02d:%02d:%02d\n"), CurrentDateTime->Hour, CurrentDateTime->Minute, CurrentDateTime->Second);
2897     fprintf(stdout, _("   Date: %4d/%02d/%02d\n"), CurrentDateTime->Year, CurrentDateTime->Month, CurrentDateTime->Day);
2898 #endif /* DEBUG */
2899
2900     CurrentDateTime->IsSet=true;
2901   } else {
2902
2903 #ifdef DEBUG
2904     fprintf(stdout, _("Message: Date and time not set in phone\n"));
2905 #endif
2906
2907     CurrentDateTime->IsSet=false;
2908   }
2909       
2910   CurrentDateTimeError=GE_NONE;
2911 }
2912
2913 GSM_Error N6110_GetDateTime(GSM_DateTime *date_time)
2914 {
2915   return N6110_PrivGetDateTime(date_time,0x11);
2916 }
2917
2918 GSM_Error N6110_PrivGetDateTime(GSM_DateTime *date_time, int msgtype)
2919 {
2920   unsigned char req[] = {N6110_FRAME_HEADER, 0x62};
2921
2922   CurrentDateTime=date_time;
2923
2924   return NULL_SendMessageSequence
2925     (50, &CurrentDateTimeError, 4, msgtype, req);
2926 }
2927
2928 void N6110_ReplyGetAlarm(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2929
2930 #ifdef DEBUG
2931   fprintf(stdout, _("Message: Alarm\n"));
2932   fprintf(stdout, _("   Alarm: %02d:%02d\n"), MessageBuffer[9], MessageBuffer[10]);
2933   fprintf(stdout, _("   Alarm is %s\n"), (MessageBuffer[8]==2) ? _("on"):_("off"));
2934 #endif /* DEBUG */
2935
2936   CurrentAlarm->Hour=MessageBuffer[9];
2937   CurrentAlarm->Minute=MessageBuffer[10];
2938   CurrentAlarm->Second=0;
2939
2940   CurrentAlarm->IsSet=(MessageBuffer[8]==2);
2941
2942   CurrentAlarmError=GE_NONE;
2943 }
2944
2945 GSM_Error N6110_GetAlarm(int alarm_number, GSM_DateTime *date_time)
2946 {
2947   return N6110_PrivGetAlarm(alarm_number,date_time,0x11);
2948 }
2949
2950 GSM_Error N6110_PrivGetAlarm(int alarm_number, GSM_DateTime *date_time, int msgtype)
2951 {
2952   unsigned char req[] = {N6110_FRAME_HEADER, 0x6d};
2953
2954   CurrentAlarm=date_time;
2955
2956   return NULL_SendMessageSequence
2957     (50, &CurrentAlarmError, 4, msgtype, req);
2958 }
2959
2960 void N6110_ReplyGetSMSCenter(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
2961   
2962   switch (MessageBuffer[3]) {
2963
2964   case 0x34:
2965
2966     CurrentMessageCenter->No=MessageBuffer[4];
2967     CurrentMessageCenter->Format=MessageBuffer[6];
2968     CurrentMessageCenter->Validity=MessageBuffer[8];
2969     sprintf(CurrentMessageCenter->Name, "%s", MessageBuffer+33);
2970
2971     sprintf(CurrentMessageCenter->DefaultRecipient, "%s", GSM_UnpackSemiOctetNumber(MessageBuffer+9,false));
2972
2973     sprintf(CurrentMessageCenter->Number, "%s", GSM_UnpackSemiOctetNumber(MessageBuffer+21,false));
2974       
2975 #ifdef DEBUG
2976     fprintf(stdout, _("Message: SMS Center received:\n"));
2977     fprintf(stdout, _("   %d. SMS Center name is %s\n"), CurrentMessageCenter->No, CurrentMessageCenter->Name);
2978     fprintf(stdout, _("   SMS Center number is %s\n"), CurrentMessageCenter->Number);
2979     fprintf(stdout, _("   Default recipient number is %s\n"), CurrentMessageCenter->DefaultRecipient);
2980       
2981     fprintf(stdout, _("   SMS Center message format is "));
2982
2983     switch (CurrentMessageCenter->Format) {
2984
2985       case GSMF_Text  : fprintf(stdout, _("Text"));   break;
2986       case GSMF_Paging: fprintf(stdout, _("Paging")); break;
2987       case GSMF_Fax   : fprintf(stdout, _("Fax"));    break;
2988       case GSMF_Email : fprintf(stdout, _("Email"));  break;
2989       default         : fprintf(stdout, _("Unknown"));
2990     }
2991
2992     fprintf(stdout, "\n");
2993
2994     fprintf(stdout, _("   SMS Center message validity is "));
2995
2996     switch (CurrentMessageCenter->Validity) {
2997
2998       case GSMV_1_Hour  : fprintf(stdout, _("1 hour"));      break;
2999       case GSMV_6_Hours : fprintf(stdout, _("6 hours"));     break;
3000       case GSMV_24_Hours: fprintf(stdout, _("24 hours"));    break;
3001       case GSMV_72_Hours: fprintf(stdout, _("72 hours"));    break;
3002       case GSMV_1_Week  : fprintf(stdout, _("1 week"));      break;
3003       case GSMV_Max_Time: fprintf(stdout, _("Maximum time"));break;
3004       default           : fprintf(stdout, _("Unknown"));
3005     }
3006
3007     fprintf(stdout, "\n");
3008
3009 #endif /* DEBUG */
3010
3011     CurrentMessageCenterError=GE_NONE;
3012
3013     break;
3014
3015   case 0x35:
3016
3017     /* Number of entries depends on SIM card */
3018
3019 #ifdef DEBUG
3020     fprintf(stdout, _("Message: SMS Center error received:\n"));
3021     fprintf(stdout, _("   The request for SMS Center failed.\n"));
3022 #endif /* DEBUG */
3023
3024     /* FIXME: appropriate error. */
3025     CurrentMessageCenterError=GE_INTERNALERROR;
3026
3027     break;  
3028
3029   }
3030 }
3031
3032 /* This function sends to the mobile phone a request for the SMS Center */
3033 GSM_Error N6110_GetSMSCenter(GSM_MessageCenter *MessageCenter)
3034 {
3035   unsigned char req[] = { N6110_FRAME_HEADER, 0x33, 0x64,
3036                           0x00 /* SMS Center Number. */
3037                         };
3038
3039   req[5]=MessageCenter->No;
3040
3041   CurrentMessageCenter=MessageCenter;
3042
3043   return NULL_SendMessageSequence
3044     (50, &CurrentMessageCenterError, 6, 0x02, req);
3045 }
3046
3047 void N6110_ReplySetSMSCenter(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3048
3049 #ifdef DEBUG
3050   fprintf(stdout, _("Message: SMS Center correctly set.\n"));
3051 #endif
3052   CurrentMessageCenterError=GE_NONE;
3053 }
3054
3055 /* This function set the SMS Center profile on the phone. */
3056 GSM_Error N6110_SetSMSCenter(GSM_MessageCenter *MessageCenter)
3057 {
3058   unsigned char req[64] = { N6110_FRAME_HEADER, 0x30, 0x64,
3059                             0x00, /* SMS Center Number. */
3060                             0x00, /* Unknown. */
3061                             0x00, /* SMS Message Format. */
3062                             0x00, /* Unknown. */
3063                             0x00, /* Validity. */
3064                             0,0,0,0,0,0,0,0,0,0,0,0, /* Default recipient number */
3065                             0,0,0,0,0,0,0,0,0,0,0,0 /* Message Center Number. */
3066                             /* Message Center Name. */
3067                           };
3068
3069   req[5]=MessageCenter->No;
3070   req[7]=MessageCenter->Format;
3071   req[9]=MessageCenter->Validity;
3072
3073   req[10]=GSM_PackSemiOctetNumber(MessageCenter->DefaultRecipient, req+11, false);
3074
3075   req[22]=GSM_PackSemiOctetNumber(MessageCenter->Number, req+23, false);
3076
3077   sprintf(req+34, "%s", MessageCenter->Name);
3078
3079   CurrentMessageCenter=MessageCenter;
3080
3081   return NULL_SendMessageSequence
3082     (50, &CurrentMessageCenterError, 35+strlen(MessageCenter->Name), 0x02, req);
3083 }
3084
3085 void N6110_ReplyGetSMSStatus(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3086
3087   switch (MessageBuffer[3]) {
3088
3089   case 0x37:
3090
3091 #ifdef DEBUG
3092     fprintf(stdout, _("Message: SMS Status Received\n"));
3093     fprintf(stdout, _("   The number of messages: %d\n"), MessageBuffer[10]);
3094     fprintf(stdout, _("   Unread messages: %d\n"), MessageBuffer[11]);
3095 #endif /* DEBUG */
3096
3097     CurrentSMSStatus->UnRead = MessageBuffer[11];
3098     CurrentSMSStatus->Number = MessageBuffer[10];
3099     
3100     CurrentSMSStatusError = GE_NONE;
3101     break;
3102
3103   case 0x38:
3104
3105 #ifdef DEBUG
3106     fprintf(stdout, _("Message: SMS Status error, probably not authorized by PIN\n"));
3107 #endif /* DEBUG */
3108
3109     CurrentSMSStatusError = GE_INTERNALERROR;
3110     break;
3111           
3112   }
3113 }
3114
3115 GSM_Error N6110_GetSMSStatus(GSM_SMSStatus *Status)
3116 {
3117   unsigned char req[] = {N6110_FRAME_HEADER, 0x36, 0x64};
3118
3119   CurrentSMSStatus = Status;
3120
3121   return NULL_SendMessageSequence
3122     (10, &CurrentSMSStatusError, 5, 0x14, req);
3123 }
3124
3125 GSM_Error N6110_GetSMSFolders ( GSM_SMSFolders *folders)
3126 {
3127   folders->number=2;
3128
3129   strcpy(folders->Folder[0].Name,"Inbox");
3130   strcpy(folders->Folder[1].Name,"Outbox");
3131   
3132   return GE_NONE;
3133 }
3134
3135 #endif /* UCLINUX */
3136
3137 GSM_Error N6110_GetIMEI(char *imei)
3138 {
3139   if (strlen(Current_IMEI)>0) {
3140     strncpy (imei, Current_IMEI, GSM_MAX_IMEI_LENGTH);
3141     return (GE_NONE);
3142   }
3143   else
3144     return (GE_TRYAGAIN);
3145 }
3146
3147 GSM_Error N6110_GetRevision(char *revision)
3148 {
3149
3150   if (strlen(Current_Revision)>0) {
3151     strncpy (revision, Current_Revision, GSM_MAX_REVISION_LENGTH);
3152     return (GE_NONE);
3153   }
3154   else
3155     return (GE_TRYAGAIN);
3156 }
3157
3158 static GSM_Error N6110_GetModel(char *model)
3159 {
3160   if (strlen(Current_Model)>0) {
3161     strncpy (model, Current_Model, GSM_MAX_MODEL_LENGTH);
3162     return (GE_NONE);
3163   }
3164   else
3165     return (GE_TRYAGAIN);
3166 }
3167
3168 #ifndef UCLINUX
3169
3170 void N6110_ReplySetDateTime(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3171
3172   switch (MessageBuffer[4]) {
3173
3174     case 0x01:
3175 #ifdef DEBUG
3176       fprintf(stdout, _("Message: Date and time set correctly\n"));
3177 #endif /* DEBUG */
3178       CurrentSetDateTimeError=GE_NONE;
3179       break;
3180       
3181     default:
3182 #ifdef DEBUG
3183       fprintf(stdout, _("Message: Date and time setting error\n"));
3184 #endif /* DEBUG */
3185       CurrentSetDateTimeError=GE_INVALIDDATETIME;
3186
3187   }
3188 }
3189
3190 /* Needs SIM card with PIN in phone */
3191 GSM_Error N6110_SetDateTime(GSM_DateTime *date_time)
3192 {
3193   return N6110_PrivSetDateTime(date_time,0x11);
3194 }
3195
3196 /* Needs SIM card with PIN in phone */
3197 GSM_Error N6110_PrivSetDateTime(GSM_DateTime *date_time, int msgtype)
3198 {
3199
3200   unsigned char req[] = { N6110_FRAME_HEADER,
3201                           0x60, /* set-time subtype */
3202                           0x01, 0x01, 0x07, /* unknown */
3203                           0x00, 0x00, /* Year (0x07cf = 1999) */
3204                           0x00, 0x00, /* Month Day */
3205                           0x00, 0x00, /* Hours Minutes */
3206                           0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
3207                         };
3208
3209   EncodeDateTime(req+7, date_time);
3210
3211   return NULL_SendMessageSequence
3212     (20, &CurrentSetDateTimeError, 14, msgtype, req);
3213 }
3214
3215 void N6110_ReplySetAlarm(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3216
3217   switch (MessageBuffer[4]) {
3218
3219     case 0x01:
3220 #ifdef DEBUG
3221       fprintf(stdout, _("Message: Alarm set correctly\n"));
3222 #endif /* DEBUG */
3223       CurrentSetAlarmError=GE_NONE;
3224       break;
3225       
3226     default:
3227 #ifdef DEBUG
3228       fprintf(stdout, _("Message: Alarm setting error\n"));
3229 #endif /* DEBUG */
3230       CurrentSetAlarmError=GE_INVALIDDATETIME;
3231
3232   }
3233 }
3234
3235 /* FIXME: we should also allow to set the alarm off :-) */
3236 GSM_Error N6110_SetAlarm(int alarm_number, GSM_DateTime *date_time)
3237 {
3238   return N6110_PrivSetAlarm(alarm_number,date_time, 0x11);
3239 }
3240
3241 /* FIXME: we should also allow to set the alarm off :-) */
3242 GSM_Error N6110_PrivSetAlarm(int alarm_number, GSM_DateTime *date_time, int msgtype)
3243 {
3244
3245   unsigned char req[] = { N6110_FRAME_HEADER,
3246                           0x6b, /* set-alarm subtype */
3247                           0x01, 0x20, 0x03, /* unknown */
3248                           0x02,       /* should be alarm on/off, but it don't works */
3249                           0x00, 0x00, /* Hours Minutes */
3250                           0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
3251                         };
3252
3253   req[8] = date_time->Hour;
3254   req[9] = date_time->Minute;
3255
3256   return NULL_SendMessageSequence
3257     (50, &CurrentSetAlarmError, 11, msgtype, req);
3258 }
3259
3260 #endif /* UCLINUX */
3261
3262 static void N6110_ReplyGetMemoryLocation(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3263
3264   /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
3265   char model[64];
3266
3267   int i, tmp, count;
3268     
3269   switch (MessageBuffer[3]) {
3270
3271   case 0x02:
3272
3273     CurrentPhonebookEntry->Empty = true;
3274
3275     count=MessageBuffer[5];
3276           
3277 #ifdef DEBUG
3278     fprintf(stdout, _("Message: Phonebook entry received:\n"));
3279     fprintf(stdout, _("   Name: "));
3280
3281     for (tmp=0; tmp <count; tmp++)
3282     {
3283       if (MessageBuffer[6+tmp]==1) fprintf(stdout, "%c", '~'); else //enables/disables blinking
3284       if (MessageBuffer[6+tmp]==0) fprintf(stdout, "%c", '`'); else //hides rest ot contents
3285       fprintf(stdout, "%c", MessageBuffer[6+tmp]);
3286     }
3287
3288     fprintf(stdout, "\n");
3289 #endif /* DEBUG */
3290
3291     while (N6110_GetModel(model)  != GE_NONE)
3292       sleep(1);
3293         
3294     if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {//pbk with Unicode
3295 #ifndef UCLINUX
3296       DecodeUnicode (CurrentPhonebookEntry->Name, MessageBuffer+6, count/2);
3297       CurrentPhonebookEntry->Name[count/2] = 0x00;
3298 #else /* UCLINUX */
3299       fprintf(stderr,"FATAL ERROR: DecodeUnicode disabled!\n");
3300       exit(1);
3301 #endif /* UCLINUX */
3302     } else {
3303       memcpy(CurrentPhonebookEntry->Name, MessageBuffer + 6, count);
3304       CurrentPhonebookEntry->Name[count] = 0x00;
3305     }
3306
3307     CurrentPhonebookEntry->Empty = false;
3308
3309     for (tmp=0; tmp <count; tmp++)
3310     {
3311       if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {//pbk with Unicode
3312         /* We check only 1'st, 3'rd, ... char */
3313         if (tmp%2!=0 && MessageBuffer[6+tmp]==1) CurrentPhonebookEntry->Name[tmp/2]='~'; //enables/disables blinking
3314         if (tmp%2!=0 && MessageBuffer[6+tmp]==0) CurrentPhonebookEntry->Name[tmp/2]='`'; //hides rest ot contents
3315       } else {
3316         if (MessageBuffer[6+tmp]==1) CurrentPhonebookEntry->Name[tmp]='~'; //enables/disables blinking
3317         if (MessageBuffer[6+tmp]==0) CurrentPhonebookEntry->Name[tmp]='`'; //hides rest ot contents
3318       }
3319     }
3320
3321     i=7+count;
3322     count=MessageBuffer[6+count];
3323
3324 #ifdef DEBUG
3325     fprintf(stdout, _("   Number: "));
3326
3327     for (tmp=0; tmp <count; tmp++)
3328       fprintf(stdout, "%c", MessageBuffer[i+tmp]);
3329
3330     fprintf(stdout, "\n");
3331 #endif /* DEBUG */
3332
3333     memcpy(CurrentPhonebookEntry->Number, MessageBuffer + i, count);
3334     CurrentPhonebookEntry->Number[count] = 0x00;
3335     CurrentPhonebookEntry->Group = MessageBuffer[i+count];
3336       
3337     /* Phone doesn't have entended phonebook */
3338     CurrentPhonebookEntry->SubEntriesCount = 0;
3339
3340     /* But for these memories data is saved and we can save it using 7110/6210 style */
3341     if (CurrentPhonebookEntry->MemoryType==GMT_DC ||
3342         CurrentPhonebookEntry->MemoryType==GMT_RC ||
3343         CurrentPhonebookEntry->MemoryType==GMT_MC) {
3344         CurrentPhonebookEntry->SubEntriesCount = 1;
3345         CurrentPhonebookEntry->SubEntries[0].EntryType=N7110_ENTRYTYPE_DATE;
3346         CurrentPhonebookEntry->SubEntries[0].NumberType=0;
3347         CurrentPhonebookEntry->SubEntries[0].BlockNumber=1;
3348         DecodeDateTime(MessageBuffer+(i+count+2),&CurrentPhonebookEntry->SubEntries[0].data.Date);
3349
3350 #ifdef DEBUG
3351       fprintf(stdout, _("   Date: "));
3352       fprintf(stdout, "%02u.%02u.%04u\n",
3353           CurrentPhonebookEntry->SubEntries[0].data.Date.Day,
3354           CurrentPhonebookEntry->SubEntries[0].data.Date.Month,
3355           CurrentPhonebookEntry->SubEntries[0].data.Date.Year);
3356       fprintf(stdout, _("   Time: "));
3357       fprintf(stdout, "%02u:%02u:%02u\n",
3358           CurrentPhonebookEntry->SubEntries[0].data.Date.Hour,
3359           CurrentPhonebookEntry->SubEntries[0].data.Date.Minute,
3360           CurrentPhonebookEntry->SubEntries[0].data.Date.Second);
3361 #endif /* DEBUG */
3362
3363       /* These values are set, when date and time unavailable in phone.
3364          Values from 3310 - in other can be different */
3365       if (CurrentPhonebookEntry->SubEntries[0].data.Date.Day==20 &&
3366           CurrentPhonebookEntry->SubEntries[0].data.Date.Month==1 &&
3367           CurrentPhonebookEntry->SubEntries[0].data.Date.Year==2118 &&
3368           CurrentPhonebookEntry->SubEntries[0].data.Date.Hour==3 &&
3369           CurrentPhonebookEntry->SubEntries[0].data.Date.Minute==14 &&
3370           CurrentPhonebookEntry->SubEntries[0].data.Date.Second==7)
3371           CurrentPhonebookEntry->SubEntriesCount = 0;
3372     }
3373
3374     /* Signal no error to calling code. */
3375     CurrentPhonebookError = GE_NONE;
3376
3377     break;
3378
3379   case 0x03:
3380
3381 #ifdef DEBUG
3382     fprintf(stdout, _("Message: Phonebook read entry error received:\n"));
3383 #endif /* DEBUG */
3384
3385     switch (MessageBuffer[4]) {
3386
3387       case 0x7d:
3388 #ifdef DEBUG
3389         fprintf(stdout, _("   Invalid memory type!\n"));
3390 #endif /* DEBUG */
3391         CurrentPhonebookError = GE_INVALIDMEMORYTYPE;
3392         break;
3393
3394       default:
3395 #ifdef DEBUG
3396         fprintf(stdout, _("   Unknown error!\n"));
3397 #endif /* DEBUG */
3398         CurrentPhonebookError = GE_INTERNALERROR;
3399     }
3400
3401     break;
3402
3403   }
3404 }
3405
3406 /* Routine to get specifed phone book location.  Designed to be called by
3407    application.  Will block until location is retrieved or a timeout/error
3408    occurs. */
3409 GSM_Error N6110_GetMemoryLocation(GSM_PhonebookEntry *entry)
3410 {
3411   unsigned char req[] = {N6110_FRAME_HEADER, 0x01, 0x00, 0x00, 0x00};
3412
3413   CurrentPhonebookEntry = entry;
3414
3415   req[4] = N6110_GetMemoryType(entry->MemoryType);
3416   req[5] = entry->Location;
3417
3418   return NULL_SendMessageSequence
3419     (50, &CurrentPhonebookError, 7, 0x03, req);
3420 }
3421
3422 static void N6110_ReplyWritePhonebookLocation(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3423
3424   switch (MessageBuffer[3]) {
3425
3426   case 0x05:
3427
3428 #ifdef DEBUG
3429     fprintf(stdout, _("Message: Phonebook written correctly.\n"));
3430 #endif /* DEBUG */
3431     CurrentPhonebookError = GE_NONE;
3432     break;
3433
3434   case 0x06:
3435
3436     switch (MessageBuffer[4]) {
3437       /* FIXME: other errors? When I send the phonebook with index of 350 it
3438          still report error 0x7d :-( */
3439       case 0x7d:
3440 #ifdef DEBUG
3441         fprintf(stdout, _("Message: Phonebook not written - name is too long.\n"));
3442 #endif /* DEBUG */
3443         CurrentPhonebookError = GE_PHBOOKNAMETOOLONG;
3444         break;
3445
3446       default:
3447 #ifdef DEBUG
3448         fprintf(stdout, _("   Unknown error!\n"));
3449 #endif /* DEBUG */
3450         CurrentPhonebookError = GE_INTERNALERROR;
3451     }
3452   }
3453 }
3454
3455 /* Routine to write phonebook location in phone. Designed to be called by
3456    application code. Will block until location is written or timeout
3457    occurs. */
3458 GSM_Error N6110_WritePhonebookLocation(GSM_PhonebookEntry *entry)
3459 {
3460   unsigned char req[128] = { N6110_FRAME_HEADER, 0x04, 0x00, 0x00 };
3461   int i=0, current=0;
3462
3463   req[4] = N6110_GetMemoryType(entry->MemoryType);
3464   req[5] = entry->Location;
3465
3466   current=7;
3467
3468   if (GetModelFeature (FN_PHONEBOOK)==F_PBK33) {
3469 #ifndef UCLINUX
3470
3471      req[6] = strlen(entry->Name)*2;
3472
3473      EncodeUnicode (req+current,entry->Name ,strlen(entry->Name));
3474      
3475      for (i=0; i<strlen(entry->Name); i++)
3476      {
3477        /* here we encode "special" chars */
3478        if (entry->Name[i]=='~') req[current+i*2]=1; //enables/disables blinking
3479        if (entry->Name[i]=='`') req[current+i*2]=0; //hides rest ot contents
3480      }
3481
3482      current+=strlen(entry->Name)*2;
3483
3484 #else /* UCLINUX */
3485
3486      fprintf(stderr,"FATAL ERROR: EncodeUnicode disabled!\n");
3487      exit(1);
3488
3489 #endif /* UCLINUX */
3490   } else {
3491
3492     req[6] = strlen(entry->Name);
3493
3494     for (i=0; i<strlen(entry->Name); i++)
3495     {
3496       req[current+i] = entry->Name[i];
3497
3498       /* here we encode "special" chars */
3499       if (entry->Name[i]=='~') req[current+i]=1; //enables/disables blinking
3500       if (entry->Name[i]=='`') req[current+i]=0; //hides rest ot contents
3501     }
3502
3503     current+=strlen(entry->Name);
3504   }
3505
3506   req[current++]=strlen(entry->Number);
3507
3508   for (i=0; i<strlen(entry->Number); i++)
3509     req[current+i] = entry->Number[i];
3510
3511   current+=strlen(entry->Number);
3512
3513   /* Jano: This allow to save 14 characters name into SIM memory, when
3514      No Group is selected. */
3515   if (entry->Group == 5)
3516     req[current++]=0xff;
3517   else
3518     req[current++]=entry->Group;
3519
3520   return NULL_SendMessageSequence
3521     (50, &CurrentPhonebookError, current, 0x03, req);
3522 }
3523
3524 #ifndef UCLINUX
3525
3526 void N6110_ReplyNetmonitor(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3527
3528   switch(MessageBuffer[3]) {
3529
3530     case 0x00:
3531 #ifdef DEBUG
3532       fprintf(stdout, _("Message: Netmonitor correctly set.\n"));
3533 #endif /* DEBUG */
3534       CurrentNetmonitorError=GE_NONE;  
3535       break;
3536       
3537     default:
3538 #ifdef DEBUG
3539       fprintf(stdout, _("Message: Netmonitor menu %d received:\n"), MessageBuffer[3]);
3540       fprintf(stdout, "%s\n", MessageBuffer+4);
3541 #endif /* DEBUG */
3542
3543       strcpy(CurrentNetmonitor, MessageBuffer+4);
3544
3545       CurrentNetmonitorError=GE_NONE;  
3546   }
3547 }
3548
3549 GSM_Error N6110_NetMonitor(unsigned char mode, char *Screen)
3550 {
3551   unsigned char req[] = { 0x00, 0x01, 0x7e, 0x00 };
3552   
3553   GSM_Error error;
3554   
3555   error=N6110_EnableExtendedCommands(0x01);
3556   if (error!=GE_NONE) return error;
3557
3558   CurrentNetmonitor=Screen;
3559
3560   req[3]=mode;
3561
3562   return NULL_SendMessageSequence
3563     (20, &CurrentNetmonitorError, 4, 0x40, req);
3564 }
3565
3566 /* Doesn't work in N3210. */
3567 /* In other allow to access phone menu without SIM card (just send any sequence) */
3568 GSM_Error N6110_SendDTMF(char *String)
3569 {
3570   unsigned char req[64] = { N6110_FRAME_HEADER, 0x50,
3571                             0x00 /* Length of DTMF string. */
3572                           };
3573                           
3574   u8 length=strlen(String);
3575
3576   if (length>59) length=59;
3577   
3578   req[4] = length;
3579   
3580   memcpy(req+5,String,length);
3581
3582   return NULL_SendMessageSequence
3583     (20, &CurrentSendDTMFError, 5+length, 0x01, req);
3584 }
3585
3586 #endif /* UCLINUX */
3587
3588 static void N6110_ReplyGetSpeedDial(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3589
3590   switch (MessageBuffer[3]) {
3591
3592   case 0x17:
3593
3594     switch (MessageBuffer[4]) {
3595       case 0x02: CurrentSpeedDialEntry->MemoryType = GMT_ME;
3596       default  : CurrentSpeedDialEntry->MemoryType = GMT_SM;
3597     }
3598       
3599     CurrentSpeedDialEntry->Location = MessageBuffer[5];
3600
3601 #ifdef DEBUG
3602     fprintf(stdout, _("Message: Speed dial entry received:\n"));
3603     fprintf(stdout, _("   Location: %d\n"), CurrentSpeedDialEntry->Location);
3604     fprintf(stdout, _("   MemoryType: %s\n"), N6110_MemoryType_String[CurrentSpeedDialEntry->MemoryType]);
3605     fprintf(stdout, _("   Number: %d\n"), CurrentSpeedDialEntry->Number);
3606 #endif /* DEBUG */
3607
3608     CurrentSpeedDialError=GE_NONE;
3609     break;
3610
3611   case 0x18:
3612
3613 #ifdef DEBUG
3614     fprintf(stdout, _("Message: Speed dial entry error\n"));
3615 #endif /* DEBUG */
3616     CurrentSpeedDialError=GE_INVALIDSPEEDDIALLOCATION;
3617     break;
3618
3619   }
3620 }
3621
3622 GSM_Error N6110_GetSpeedDial(GSM_SpeedDial *entry)
3623 {
3624
3625   unsigned char req[] = { N6110_FRAME_HEADER,
3626                           0x16,
3627                           0x00  /* The number of speed dial. */
3628                         };
3629
3630   CurrentSpeedDialEntry = entry;
3631
3632   req[4] = entry->Number;
3633
3634   return NULL_SendMessageSequence
3635     (20, &CurrentSpeedDialError, 5, 0x03, req);
3636 }
3637
3638 static void N6110_ReplySetSpeedDial(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3639
3640   switch (MessageBuffer[3]) {
3641
3642   case 0x1a:
3643
3644 #ifdef DEBUG
3645     fprintf(stdout, _("Message: Speed dial entry set.\n"));
3646 #endif /* DEBUG */
3647     CurrentSpeedDialError=GE_NONE;
3648     break;
3649
3650   case 0x1b:
3651
3652 #ifdef DEBUG
3653     fprintf(stdout, _("Message: Speed dial entry setting error.\n"));
3654 #endif /* DEBUG */
3655     CurrentSpeedDialError=GE_INVALIDSPEEDDIALLOCATION;
3656     break;
3657
3658   }
3659 }
3660
3661 GSM_Error N6110_SetSpeedDial(GSM_SpeedDial *entry)
3662 {
3663
3664   unsigned char req[] = { N6110_FRAME_HEADER,
3665                           0x19,
3666                           0x00, /* Number */
3667                           0x00, /* Memory Type */
3668                           0x00  /* Location */
3669                         };
3670
3671   req[4] = entry->Number;
3672
3673   switch (entry->MemoryType) {
3674     case GMT_ME: req[5] = 0x02;
3675     default    : req[5] = 0x03;
3676   }
3677
3678   req[6] = entry->Location;
3679
3680   return NULL_SendMessageSequence
3681     (20, &CurrentSpeedDialError, 7, 0x03, req);
3682 }
3683
3684 #ifndef UCLINUX
3685
3686 /* This function finds parts of SMS in frame used in new Nokia phones
3687    in internal protocols (they're coded according to GSM 03.40), copies them
3688    to GSM_ETSISMSMessage and calls GSM_DecodeETSISMS to decode
3689    GSM_ETSISMSMessage to GSM_SMSMessage structure */
3690 GSM_Error GSM_DecodeNokiaSMSFrame(GSM_SMSMessage *SMS, unsigned char *req, int length)
3691 {
3692   SMS_MessageType PDU=SMS_Deliver;
3693   GSM_ETSISMSMessage ETSI;
3694   int offset=0,i;
3695
3696   ETSI.firstbyte=req[12];
3697
3698   /* See GSM 03.40 section 9.2.3.1 */
3699   if ((ETSI.firstbyte & 0x03) == 0x01) PDU=SMS_Submit;
3700   if ((ETSI.firstbyte & 0x03) == 0x02) PDU=SMS_Status_Report;
3701
3702   switch (PDU) {
3703     case SMS_Submit       : offset=5;break;
3704     case SMS_Deliver      : offset=4;break;
3705     case SMS_Status_Report: offset=3;break;
3706     default:                break;
3707   }
3708
3709   for (i=0;i<req[0]+1;i++)
3710     ETSI.SMSCNumber[i]=req[i];
3711
3712   for (i=0;i<((req[12+offset]+1)/2+1)+1;i++)
3713     ETSI.Number[i]=req[i+12+offset];
3714
3715   switch (PDU) {
3716     case SMS_Submit:
3717       ETSI.TPDCS=req[10+offset];
3718       ETSI.TPUDL=req[11+offset];
3719       ETSI.TPVP=0;  //no support for now
3720       ETSI.TPPID=0; //no support for now
3721       for(i=31+offset;i<length;i++)
3722         ETSI.MessageText[i-31-offset]=req[i];
3723       break;
3724     case SMS_Deliver:
3725       ETSI.TPDCS=req[10+offset];
3726       ETSI.TPUDL=req[11+offset];
3727       ETSI.TPPID=0; //no support for now
3728       for(i=31+offset;i<length;i++)
3729         ETSI.MessageText[i-31-offset]=req[i];
3730       for(i=0;i<7;i++)
3731         ETSI.DeliveryDateTime[i]=req[i+24+offset];
3732       break;
3733     case SMS_Status_Report:
3734       for(i=0;i<7;i++)
3735         ETSI.DeliveryDateTime[i]=req[i+24+offset];
3736       ETSI.TPStatus=req[14];
3737       for(i=0;i<7;i++)
3738         ETSI.SMSCDateTime[i]=req[i+34];
3739       break;
3740     default:
3741       break;
3742   }
3743
3744   GSM_DecodeETSISMS(SMS, &ETSI);
3745
3746   SMS->Name[0]=0;
3747
3748   return GE_NONE;
3749 }
3750
3751 void N6110_ReplyGetSMSMessage(u16 MessageLength, u8 *MessageBuffer, u8 MessageType) {
3752
3753   int offset;
3754   
3755   switch (MessageBuffer[3]) {
3756
3757   case 0x08:
3758
3759     switch (MessageBuffer[7]) {
3760
3761       case 0x00:
3762         CurrentSMSMessage->Type = GST_SMS;
3763         CurrentSMSMessage->folder=GST_INBOX;
3764         offset=4;
3765         break;
3766
3767       case 0x01:
3768         CurrentSMSMessage->Type = GST_DR;
3769         CurrentSMSMessage->folder=GST_INBOX;
3770         offset=3;
3771         break;
3772
3773       case 0x02:
3774         CurrentSMSMessage->Type = GST_SMS;
3775         CurrentSMSMessage->folder=GST_OUTBOX;
3776         offset=5;
3777         break;
3778
3779       default:
3780         CurrentSMSMessage->Type = GST_UN;
3781         offset=4;
3782         break;
3783
3784     }
3785
3786     /* Field Short Message Status - MessageBuffer[4] seems not to be
3787        compliant with GSM 07.05 spec.
3788        Meaning     Nokia protocol       GMS spec
3789        ----------------------------------------------------
3790        MO Sent     0x05                 0x07 or 0x01
3791        MO Not sent 0x07                 0x06 or 0x00
3792        MT Read     0x01                 0x05 or 0x01
3793        MT Not read 0x03                 0x04 or 0x00
3794        ----------------------------------------------------
3795        See GSM 07.05 section 2.5.2.6 and correct me if I'm wrong.
3796        
3797                                          Pawel Kot */
3798
3799     if (MessageBuffer[4] & 0x02) CurrentSMSMessage->Status = GSS_NOTSENTREAD;
3800                             else CurrentSMSMessage->Status = GSS_SENTREAD;
3801
3802 #ifdef DEBUG
3803     fprintf(stdout, _("Number: %d\n"), MessageBuffer[6]);
3804
3805     if (CurrentSMSMessage->folder!=1) { //GST_OUTBOX
3806       fprintf(stdout, _("Message: Received SMS (mobile terminated)\n"));
3807     } else {
3808       fprintf(stdout, _("Message: Outbox message (mobile originated)\n"));
3809     }
3810
3811     if (CurrentSMSMessage->Type == GST_DR) fprintf(stdout, _("   Delivery Report\n"));
3812     if (CurrentSMSMessage->Type == GST_UN) fprintf(stdout, _("   Unknown type\n"));
3813
3814     if (CurrentSMSMessage->folder==1) { //GST_OUTBOX
3815       if (CurrentSMSMessage->Status) fprintf(stdout, _("   Sent\n"));
3816                                 else fprintf(stdout, _("   Not sent\n"));
3817     } else {
3818       if (CurrentSMSMessage->Status) fprintf(stdout, _("   Read\n"));
3819                                 else fprintf(stdout, _("   Not read\n"));
3820     }
3821 #endif
3822
3823     CurrentSMSPointer=GSM_DecodeNokiaSMSFrame(CurrentSMSMessage, MessageBuffer+8, MessageLength-8);
3824
3825     CurrentSMSMessage->MemoryType = MessageBuffer[5];
3826     CurrentSMSMessage->MessageNumber = MessageBuffer[6];
3827  
3828     /* Signal no error to calling code. */
3829     CurrentSMSMessageError = GE_NONE;
3830
3831 #ifdef DEBUG
3832     fprintf(stdout, "\n");
3833 #endif
3834
3835     break;
3836
3837   case 0x09:
3838
3839     /* We have requested invalid or empty location. */
3840
3841 #ifdef DEBUG
3842     fprintf(stdout, _("Message: SMS reading failed\n"));
3843
3844     switch (MessageBuffer[4]) {
3845       case 0x02:
3846         fprintf(stdout, _("   Invalid location!\n"));break;
3847       case 0x07:
3848         fprintf(stdout, _("   Empty SMS location.\n"));break;
3849       case 0x0c:
3850         fprintf(stdout, _("   No access to memory (no PIN on card ?)\n"));break;
3851       default:      
3852         fprintf(stdout, _("   Error code %i - please report it \n"),MessageBuffer[4]);break;
3853     }
3854 #endif /* DEBUG */
3855
3856     switch (MessageBuffer[4]) {
3857       case 0x02:CurrentSMSMessageError = GE_INVALIDSMSLOCATION;break;
3858       case 0x07:CurrentSMSMessageError = GE_EMPTYSMSLOCATION;break;
3859       case 0x0c:CurrentSMSMessageError = GE_NOACCESS;break;
3860       default  :CurrentSMSMessageError = GE_UNKNOWN;break;
3861     }
3862
3863     break;
3864
3865   }
3866 }
3867
3868 GSM_Error N6110_GetSMSMessage(GSM_SMSMessage *message)
3869 {
3870
3871   unsigned char req[] = { N6110_FRAME_HEADER,
3872                           0x07,
3873                           0x02, /* Unknown */
3874                           0x00, /* Location */
3875                           0x01, 0x64};
3876
3877   int timeout = 60;