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