Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
[gnokii.git] / common / phones / nk7110.c
1 /*
2
3   $Id$
4
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Copyright (C) 2000 Hugh Blemings & Pavel Janík ml.
10   Copytight (C) 2000 Chris Kemp
11
12   Released under the terms of the GNU GPL, see file COPYING for more details.
13
14   This file provides functions specific to the 7110 series. 
15   See README for more details on supported mobile phones.
16
17   The various routines are called P7110_(whatever).
18
19   $Log$
20   Revision 1.1.1.1.12.1  2001/11/27 23:34:48  short
21   Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
22
23   Revision 1.1.1.1.8.1  2001/11/27 23:06:09  short
24   Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
25
26   Revision 1.1.1.1.2.1  2001/11/27 22:48:37  short
27   Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
28
29   Revision 1.1.1.2  2001/11/27 22:01:19  short
30   :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
31
32   Revision 1.28  2001/11/27 12:25:01  pkot
33   Cleanup
34
35   Revision 1.27  2001/11/22 17:56:53  pkot
36   smslib update. sms sending
37
38   Revision 1.26  2001/11/19 17:09:59  pkot
39   Bugfixes
40
41   Revision 1.25  2001/11/19 16:24:31  pkot
42   Grrrr... I should have check if I have fixed this typo
43
44   Revision 1.24  2001/11/19 15:53:16  pkot
45   Typos
46
47   Revision 1.23  2001/11/19 13:46:42  pkot
48   reading unread SMS in 6210 from Inbox. Folder updates (Markus Plail)
49
50   Revision 1.22  2001/11/17 20:18:32  pkot
51   Added dau9p connection type for 6210/7110
52
53   Revision 1.21  2001/11/17 16:44:07  pkot
54   Cleanup. Reading SMS for 6100 series. Not that it has some bugs more and does not support UDH yet
55
56   Revision 1.20  2001/11/15 12:15:04  pkot
57   smslib updates. begin work on sms in 6100 series
58
59   Revision 1.19  2001/11/15 12:12:34  pkot
60   7110 and 6110 series phones introduce as Nokia
61
62   Revision 1.18  2001/11/15 12:04:06  pkot
63   Faster initialization for 6100 series (don't check for dlr3 cable)
64
65   Revision 1.17  2001/11/14 10:48:03  pkot
66   6210/7110 debug cleanups
67
68   Revision 1.16  2001/11/13 16:12:21  pkot
69   Preparing libsms to get to work. 6210/7110 SMS and SMS Folder updates
70
71   Revision 1.15  2001/11/08 16:47:48  pkot
72   Start fiddling with 7110 and SMS
73
74   Revision 1.14  2001/09/09 21:45:49  machek
75   Cleanups from Ladislav Michl <ladis@psi.cz>:
76
77   *) do *not* internationalize debug messages
78
79   *) some whitespace fixes, do not use //
80
81   *) break is unneccessary after return
82
83   Revision 1.13  2001/08/16 23:59:32  pkot
84   Fixed (hopefully) timezone mismash (Sheldon Hearn)
85
86   Revision 1.12  2001/08/09 12:34:34  pkot
87   3330 and 6250 support - I have no idea if it does work (mygnokii)
88
89   Revision 1.11  2001/07/05 10:54:53  pkot
90   Solaris 2.7 fixes - should be harmless for other OSes (Michael Wiedmann)
91
92   Revision 1.10  2001/06/27 23:52:49  pkot
93   7110/6210 updates (Marian Jancar)
94
95   Revision 1.9  2001/06/10 23:49:49  pkot
96   Small fixes to hide compilation warnings and allow gnokii.c to compile
97
98   Revision 1.8  2001/05/24 20:47:30  chris
99   More updating of 7110 code and some of xgnokii_lowlevel changed over.
100
101   Revision 1.7  2001/05/07 16:24:04  pkot
102   DLR-3P temporary fix. How should I do it better?
103
104   Revision 1.6  2001/03/23 13:40:24  chris
105   Pavel's patch and a few fixes.
106
107   Revision 1.5  2001/03/22 16:17:06  chris
108   Tidy-ups and fixed gnokii/Makefile and gnokii/ChangeLog which I somehow corrupted.
109
110   Revision 1.4  2001/03/21 23:36:06  chris
111   Added the statemachine
112   This will break gnokii --identify and --monitor except for 6210/7110
113
114   Revision 1.3  2001/03/13 01:24:03  pkot
115   Code cleanup - no warnings during compilation
116
117   Revision 1.2  2001/03/13 01:23:18  pkot
118   Windows updates (Manfred Jonsson)
119
120   Revision 1.1  2001/02/21 19:57:07  chris
121   More fiddling with the directory layout
122
123   Revision 1.1  2001/02/16 14:29:53  chris
124   Restructure of common/.  Fixed a problem in fbus-phonet.c
125   Lots of dprintfs for Marcin
126   Any size xpm can now be loaded (eg for 7110 startup logos)
127   nk7110 code detects 7110/6210 and alters startup logo size to suit
128   Moved Marcin's extended phonebook code into gnokii.c
129
130   Revision 1.7  2001/02/06 21:15:35  chris
131   Preliminary irda support for 7110 etc.  Not well tested!
132
133   Revision 1.6  2001/02/03 23:56:15  chris
134   Start of work on irda support (now we just need fbus-irda.c!)
135   Proper unicode support in 7110 code (from pkot)
136
137   Revision 1.5  2001/02/01 15:17:31  pkot
138   Fixed --identify and added Manfred's manufacturer patch
139
140   Revision 1.4  2001/01/29 17:14:42  chris
141   dprintf now in misc.h (and fiddling with 7110 code)
142
143   Revision 1.3  2001/01/23 15:32:41  chris
144   Pavel's 'break' and 'static' corrections.
145   Work on logos for 7110.
146
147   Revision 1.2  2001/01/17 02:54:54  chris
148   More 7110 work.  Use with care! (eg it is not possible to delete phonebook entries)
149   I can now edit my phonebook in xgnokii but it is 'work in progress'.
150
151   Revision 1.1  2001/01/14 22:46:59  chris
152   Preliminary 7110 support (dlr9 only) and the beginnings of a new structure
153
154 */
155
156 #include <string.h>
157 #include <stdlib.h>
158 #include <ctype.h>
159
160 #define __phones_nk7110_c  /* Turn on prototypes in phones/nk7110.h */
161 #include "misc.h"
162 #include "gsm-common.h"
163 #include "phones/generic.h"
164 #include "phones/nk7110.h"
165 #include "links/fbus.h"
166 #include "links/fbus-phonet.h"
167 #include "phones/nokia.h"
168 #include "gsm-encoding.h"
169
170 #ifdef WIN32
171 #define snprintf _snprintf
172 #endif
173
174 /* Some globals */
175
176 static GSM_IncomingFunctionType P7110_IncomingFunctions[] = {
177         { P7110_MSG_FOLDER,     P7110_IncomingFolder },
178         { P7110_MSG_SMS,        P7110_IncomingSMS },
179         { P7110_MSG_PHONEBOOK,  P7110_IncomingPhonebook },
180         { P7110_MSG_NETSTATUS,  P7110_IncomingNetwork },
181         { P7110_MSG_CALENDAR,   P7110_IncomingCalendar },
182         { P7110_MSG_BATTERY,    P7110_IncomingBattLevel },
183         { P7110_MSG_CLOCK,      P7110_IncomingClock },
184         { P7110_MSG_IDENTITY,   P7110_Incoming0x1b },
185         { P7110_MSG_STLOGO,     P7110_IncomingStartup },
186         { 0, NULL }
187 };
188
189 GSM_Phone phone_nokia_7110 = {
190         P7110_IncomingFunctions,
191         PGEN_IncomingDefault,
192         /* Mobile phone information */
193         {
194                 "7110|6210|6250", /* Supported models */
195                 7,                     /* Max RF Level */
196                 0,                     /* Min RF Level */
197                 GRF_Percentage,        /* RF level units */
198                 7,                     /* Max Battery Level */
199                 0,                     /* Min Battery Level */
200                 GBU_Percentage,        /* Battery level units */
201                 GDT_DateTime,          /* Have date/time support */
202                 GDT_TimeOnly,            /* Alarm supports time only */
203                 1,                     /* Alarms available - FIXME */
204                 60, 96,                /* Startup logo size - 7110 is fixed at init*/
205                 21, 78,                /* Op logo size */
206                 14, 72                 /* Caller logo size */
207         },
208         P7110_Functions
209 };
210
211 /* FIXME - a little macro would help here... */
212
213 static GSM_Error P7110_Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state)
214 {
215         switch (op) {
216         case GOP_Init:
217                 return P7110_Initialise(state);
218         case GOP_GetModel:
219                 return P7110_GetModel(data, state);
220         case GOP_GetRevision:
221                 return P7110_GetRevision(data, state);
222         case GOP_GetImei:
223                 return P7110_GetIMEI(data, state);
224         case GOP_Identify:
225                 return P7110_Identify(data, state);
226         case GOP_GetBatteryLevel:
227                 return P7110_GetBatteryLevel(data, state);
228         case GOP_GetRFLevel:
229                 return P7110_GetRFLevel(data, state);
230         case GOP_GetMemoryStatus:
231                 return P7110_GetMemoryStatus(data, state);
232         case GOP_GetBitmap:
233                 return P7110_GetBitmap(data, state);
234         case GOP_SetBitmap:
235                 return P7110_SetBitmap(data, state);
236         case GOP_ReadPhonebook:
237                 return P7110_ReadPhonebook(data, state);
238         case GOP_WritePhonebook:
239                 return P7110_WritePhonebookLocation(data, state);
240         case GOP_GetNetworkInfo:
241                 return P7110_GetNetworkInfo(data, state);
242         case GOP_GetSpeedDial:
243                 return P7110_GetSpeedDial(data, state);
244         case GOP_GetSMSCenter:
245                 return P7110_GetSMSCenter(data, state);
246         case GOP_GetDateTime:
247                 return P7110_GetClock(P7110_SUBCLO_GET_DATE, data, state);
248         case GOP_GetAlarm:
249                 return P7110_GetClock(P7110_SUBCLO_GET_ALARM, data, state);
250         case GOP_GetCalendarNote:
251                 return P7110_GetCalendarNote(data, state);
252         case GOP_GetSMS:
253                 return P7110_GetSMS(data, state);
254         case GOP_SendSMS:
255                 return P7110_SendSMS(data, state);
256 /* I'm not sure yet if folder functions will be shared or local
257         case GOP_GetSMSFolders:
258                 return P7110_GetSMSFolders(data, state);
259         case GOP_GetSMSFolderStatus:
260         return P7110_GetSMSFolderStatus(data, state);*/
261         default:
262                 return GE_NOTIMPLEMENTED;
263         }
264 }
265
266 /* LinkOK is always true for now... */
267 bool P7110_LinkOK = true;
268
269 /* Initialise is the only function allowed to 'use' state */
270 static GSM_Error P7110_Initialise(GSM_Statemachine *state)
271 {
272         GSM_Data data;
273         char model[10];
274         GSM_Error err;
275         int try = 0, connected = 0;
276
277         /* Copy in the phone info */
278         memcpy(&(state->Phone), &phone_nokia_7110, sizeof(GSM_Phone));
279
280         dprintf("Connecting\n");
281         while (!connected) {
282                 switch (state->Link.ConnectionType) {
283                 case GCT_DAU9P:
284                         if (try == 0) try = 1;
285                 case GCT_Serial:
286                         if (try > 1) return GE_NOTSUPPORTED;
287                         err = FBUS_Initialise(&(state->Link), state, 1 - try);
288                         break;
289                 case GCT_Infrared:
290                 case GCT_Irda:
291                         if (try > 0) return GE_NOTSUPPORTED;
292                         err = PHONET_Initialise(&(state->Link), state);
293                         break;
294                 default:
295                         return GE_NOTSUPPORTED;
296                         break;
297                 }
298
299                 if (err != GE_NONE) {
300                         dprintf("Error in link initialisation: %d\n", err);
301                         try++;
302                         continue;
303                 }
304
305                 SM_Initialise(state);
306
307                 /* Now test the link and get the model */
308                 GSM_DataClear(&data);
309                 data.Model = model;
310                 if (state->Phone.Functions(GOP_GetModel, &data, state) != GE_NONE) try++;
311                 else connected = 1;
312         }
313         /* Check for 7110 and alter the startup logo size */
314         if (strcmp(model, "NSE-5") == 0) {
315                 state->Phone.Info.StartupLogoH = 65;
316                 dprintf("7110 detected - startup logo height set to 65\n");
317         }
318         return GE_NONE;
319 }
320
321 static GSM_Error P7110_GetModel(GSM_Data *data, GSM_Statemachine *state)
322 {
323         unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x01, 0x32};
324   
325         dprintf("Getting model...\n");
326         if (SM_SendMessage(state, 6, 0x1b, req)!=GE_NONE) return GE_NOTREADY;
327         return SM_Block(state, data, 0x1b);
328 }
329
330 static GSM_Error P7110_GetRevision(GSM_Data *data, GSM_Statemachine *state)
331 {
332         unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x01, 0x32};
333   
334         dprintf("Getting revision...\n");
335         if (SM_SendMessage(state, 6, 0x1b, req)!=GE_NONE) return GE_NOTREADY;
336         return SM_Block(state, data, 0x1b);
337 }
338
339 static GSM_Error P7110_GetIMEI(GSM_Data *data, GSM_Statemachine *state)
340 {
341         unsigned char req[] = {FBUS_FRAME_HEADER, 0x01};
342   
343         dprintf("Getting imei...\n");
344         if (SM_SendMessage(state, 4, 0x1b, req)!=GE_NONE) return GE_NOTREADY;
345         return SM_Block(state, data, 0x1b);
346 }
347
348 static GSM_Error P7110_GetBatteryLevel(GSM_Data *data, GSM_Statemachine *state)
349 {
350         unsigned char req[] = {FBUS_FRAME_HEADER, 0x02};
351
352         dprintf("Getting battery level...\n");
353         if (SM_SendMessage(state, 4, 0x17, req) != GE_NONE) return GE_NOTREADY;
354         return SM_Block(state, data, 0x17);
355 }
356
357 static GSM_Error P7110_IncomingBattLevel(int messagetype, unsigned char *message, int length, GSM_Data *data)
358 {
359         switch (message[3]) {
360         case 0x03:
361                 if (data->BatteryLevel) { 
362                         *(data->BatteryUnits) = GBU_Percentage;
363                         *(data->BatteryLevel) = message[5];
364                         dprintf("Battery level %f\n",*(data->BatteryLevel));
365                 }
366                 break;
367         default:
368                 dprintf("Unknown subtype of type 0x17 (%d)\n", message[3]);
369                 return GE_UNKNOWN;
370         }
371         return GE_NONE;
372 }
373
374 static GSM_Error P7110_GetRFLevel(GSM_Data *data, GSM_Statemachine *state)
375 {
376         unsigned char req[] = {FBUS_FRAME_HEADER, 0x81};
377
378         dprintf("Getting rf level...\n");
379         if (SM_SendMessage(state, 4, 0x0a, req) != GE_NONE) return GE_NOTREADY;
380         return SM_Block(state, data, 0x0a);
381 }
382
383 static GSM_Error P7110_GetNetworkInfo(GSM_Data *data, GSM_Statemachine *state)
384 {
385         unsigned char req[] = {FBUS_FRAME_HEADER, 0x70};
386
387         dprintf("Getting Network Info...\n");
388         if (SM_SendMessage(state, 4, 0x0a, req) != GE_NONE) return GE_NOTREADY;
389         return SM_Block(state, data, 0x0a);
390 }
391
392 static GSM_Error P7110_IncomingNetwork(int messagetype, unsigned char *message, int length, GSM_Data *data)
393 {
394         unsigned char *blockstart;
395         int i;
396         
397         switch (message[3]) {
398         case 0x71:
399                 blockstart = message + 6;
400                 for (i = 0; i < message[4]; i++) {
401                         switch (blockstart[0]) {
402                         case 0x01:  /* Operator details */
403                                 /* Network code is stored as 0xBA 0xXC 0xED ("ABC DE"). */
404                                 if (data->NetworkInfo) {
405                                         /* Is this correct? */
406                                         data->NetworkInfo->CellID[0]=blockstart[4];
407                                         data->NetworkInfo->CellID[1]=blockstart[5];
408                                         data->NetworkInfo->LAC[0]=blockstart[6];
409                                         data->NetworkInfo->LAC[1]=blockstart[7];
410                                         data->NetworkInfo->NetworkCode[0] = '0' + (blockstart[8] & 0x0f);
411                                         data->NetworkInfo->NetworkCode[1] = '0' + (blockstart[8] >> 4);
412                                         data->NetworkInfo->NetworkCode[2] = '0' + (blockstart[9] & 0x0f);
413                                         data->NetworkInfo->NetworkCode[3] = ' ';
414                                         data->NetworkInfo->NetworkCode[4] = '0' + (blockstart[10] & 0x0f);
415                                         data->NetworkInfo->NetworkCode[5] = '0' + (blockstart[10] >> 4);
416                                         data->NetworkInfo->NetworkCode[6] = 0;
417                                 }
418                                 if (data->Bitmap) {
419                                         data->Bitmap->netcode[0] = '0' + (blockstart[8] & 0x0f);
420                                         data->Bitmap->netcode[1] = '0' + (blockstart[8] >> 4);
421                                         data->Bitmap->netcode[2] = '0' + (blockstart[9] & 0x0f);
422                                         data->Bitmap->netcode[3] = ' ';
423                                         data->Bitmap->netcode[4] = '0' + (blockstart[10] & 0x0f);
424                                         data->Bitmap->netcode[5] = '0' + (blockstart[10] >> 4);
425                                         data->Bitmap->netcode[6] = 0;
426                                         dprintf("Operator %s ",data->Bitmap->netcode);
427                                 }
428                                 break;
429                         case 0x04: /* Logo */
430                                 if (data->Bitmap) {
431                                         dprintf("Op logo received ok ");
432                                         data->Bitmap->type = GSM_OperatorLogo;
433                                         data->Bitmap->size = blockstart[5]; /* Probably + [4]<<8 */
434                                         data->Bitmap->height = blockstart[3];
435                                         data->Bitmap->width = blockstart[2];
436                                         memcpy(data->Bitmap->bitmap, blockstart + 8, data->Bitmap->size);
437                                         dprintf("Logo (%dx%d) ", data->Bitmap->height, data->Bitmap->width);
438                                 }
439                                 break;
440                         default:
441                                 dprintf("Unknown operator block %d\n", blockstart[0]);
442                                 break;
443                         }
444                         blockstart += blockstart[1];
445                 }
446                 break;
447         case 0x82:
448                 if (data->RFLevel) { 
449                         *(data->RFUnits) = GRF_Percentage;
450                         *(data->RFLevel) = message[4];
451                         dprintf("RF level %f\n",*(data->RFLevel));
452                 }
453                 break;
454         case 0xa4:
455                 dprintf("Op Logo Set OK\n");
456                 break;
457         default:
458                 dprintf("Unknown subtype of type 0x0a (%d)\n", message[3]);
459                 return GE_UNKNOWN;
460         }
461         return GE_NONE;
462 }
463
464 static GSM_Error P7110_GetMemoryStatus(GSM_Data *data, GSM_Statemachine *state)
465 {
466         unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x00, 0x00};
467       
468         dprintf("Getting memory status...\n");
469         req[5] = GetMemoryType(data->MemoryStatus->MemoryType);
470         if (SM_SendMessage(state, 6, 0x03, req) != GE_NONE) return GE_NOTREADY;
471         return SM_Block(state, data, 0x03);
472 }
473
474 static GSM_Error P7110_IncomingPhonebook(int messagetype, unsigned char *message, int length, GSM_Data *data)
475 {
476         unsigned char *blockstart;
477         unsigned char blocks;
478         unsigned char subblockcount;
479         char *str;
480         int i;
481         GSM_SubPhonebookEntry* subEntry = NULL;
482
483         PGEN_DebugMessage(messagetype, message, length);
484
485         switch (message[3]) {
486         case 0x04:  /* Get status response */
487                 if (data->MemoryStatus) {
488                         if (message[5] != 0xff) {
489                                 data->MemoryStatus->Used = (message[16] << 8) + message[17];
490                                 data->MemoryStatus->Free = ((message[14] << 8) + message[15]) - data->MemoryStatus->Used;
491                                 dprintf("Memory status - location = %d\n", (message[8] << 8) + message[9]);
492                         } else {
493                                 dprintf("Unknown error getting mem status\n");
494                                 return GE_NOTIMPLEMENTED;
495                         }
496                 }
497                 break;
498         case 0x08:  /* Read Memory response */
499                 if (data->PhonebookEntry) {
500                         data->PhonebookEntry->Empty = true;
501                         data->PhonebookEntry->Group = 0;
502                         data->PhonebookEntry->Name[0] = '\0';
503                         data->PhonebookEntry->Number[0] = '\0';
504                         data->PhonebookEntry->SubEntriesCount = 0;
505                         data->PhonebookEntry->Date.Year = 0;
506                         data->PhonebookEntry->Date.Month = 0;
507                         data->PhonebookEntry->Date.Day = 0;
508                         data->PhonebookEntry->Date.Hour = 0;
509                         data->PhonebookEntry->Date.Minute = 0;
510                         data->PhonebookEntry->Date.Second = 0;
511                 }
512                 if (message[6] == 0x0f) { // not found
513                         if (message[10] == 0x34 || message[10] == 0x33 || message[10] == 0x30) {
514                                 dprintf("Invalid caller location\n");
515                                 return GE_INVALIDPHBOOKLOCATION;
516                         } else {
517                                 dprintf("Unknown error getting phonebook\n");
518                                 return GE_NOTIMPLEMENTED;
519                         }
520                 }
521                 dprintf("Received phonebook info\n");
522                 blocks     = message[17];        
523                 blockstart = message + 18;
524                 subblockcount = 0;
525            
526                 for (i = 0; i < blocks; i++) {
527                         if (data->PhonebookEntry)
528                                 subEntry = &data->PhonebookEntry->SubEntries[subblockcount];
529                         switch(blockstart[0]) {
530                         case P7110_ENTRYTYPE_POINTER:   /* Pointer */
531                                 switch (message[11]) {  /* Memory type */
532                                 case P7110_MEMORY_SPEEDDIALS:   /* Speed dial numbers */
533                                         if ((data != NULL) && (data->SpeedDial != NULL)) {
534                                                 data->SpeedDial->Location = (((unsigned int)blockstart[6]) << 8) + blockstart[7];
535                                                 switch(blockstart[8]) {
536                                                 case 0x05:
537                                                         data->SpeedDial->MemoryType = GMT_ME;
538                                                         str = "phone";
539                                                         break;
540                                                 case 0x06:
541                                                         str = "SIM";
542                                                         data->SpeedDial->MemoryType = GMT_SM;
543                                                         break;
544                                                 default:
545                                                         str = "unknown";
546                                                         data->SpeedDial->MemoryType = GMT_XX;
547                                                         break;
548                                                 }
549                                         }
550                                         
551                                         dprintf("Speed dial pointer: %i in %s\n", data->SpeedDial->Location, str);
552                                         
553                                         break;
554                                 default:
555                                         /* FIXME: is it possible? */
556                                         dprintf("Wrong memory type(?)\n");
557                                         break;
558                                 }
559                                 
560                                 break;
561                         case P7110_ENTRYTYPE_NAME:      /* Name */
562                                 if (data->Bitmap) {
563                                         DecodeUnicode(data->Bitmap->text, (blockstart + 6), blockstart[5] / 2);
564                                         dprintf("Name: %s\n", data->Bitmap->text);
565                                 } else if (data->PhonebookEntry) {
566                                         DecodeUnicode(data->PhonebookEntry->Name, (blockstart + 6), blockstart[5] / 2);
567                                         data->PhonebookEntry->Empty = false;
568                                         dprintf("   Name: %s\n", data->PhonebookEntry->Name);
569                                 }
570                                 break;
571                         case P7110_ENTRYTYPE_EMAIL:
572                         case P7110_ENTRYTYPE_POSTAL:
573                         case P7110_ENTRYTYPE_NOTE:
574                                 if (data->PhonebookEntry) {
575                                         subEntry->EntryType   = blockstart[0];
576                                         subEntry->NumberType  = 0;
577                                         subEntry->BlockNumber = blockstart[4];
578                                         DecodeUnicode(subEntry->data.Number, (blockstart + 6), blockstart[5] / 2);
579                                         dprintf("   Type: %d (%02x)\n", subEntry->EntryType, subEntry->EntryType);
580                                         dprintf("   Text: %s\n", subEntry->data.Number);
581                                         subblockcount++;
582                                         data->PhonebookEntry->SubEntriesCount++;
583                                 }
584                                 break;
585                         case P7110_ENTRYTYPE_NUMBER:
586                                 if (data->PhonebookEntry) {
587                                         subEntry->EntryType   = blockstart[0];
588                                         subEntry->NumberType  = blockstart[5];
589                                         subEntry->BlockNumber = blockstart[4];
590                                         DecodeUnicode(subEntry->data.Number, (blockstart + 10), blockstart[9] / 2);
591                                         if (!subblockcount) strcpy(data->PhonebookEntry->Number, subEntry->data.Number);
592                                         dprintf("   Type: %d (%02x)\n", subEntry->NumberType, subEntry->NumberType);
593                                         dprintf(" Number: %s\n", subEntry->data.Number);                                        
594                                         subblockcount++;
595                                         data->PhonebookEntry->SubEntriesCount++;
596                                 }
597                                 break;
598                         case P7110_ENTRYTYPE_RINGTONE:  /* Ringtone */
599                                 if (data->Bitmap) {
600                                         data->Bitmap->ringtone = blockstart[5];
601                                         dprintf("Ringtone no. %d\n", data->Bitmap->ringtone);
602                                 }
603                                 break;
604                         case P7110_ENTRYTYPE_DATE:
605                                 if (data->PhonebookEntry) {
606                                         subEntry->EntryType=blockstart[0];
607                                         subEntry->NumberType=blockstart[5];
608                                         subEntry->BlockNumber=blockstart[4];
609                                         subEntry->data.Date.Year=(blockstart[6] << 8) + blockstart[7];
610                                         subEntry->data.Date.Month  = blockstart[8];
611                                         subEntry->data.Date.Day    = blockstart[9];
612                                         subEntry->data.Date.Hour   = blockstart[10];
613                                         subEntry->data.Date.Minute = blockstart[11];
614                                         subEntry->data.Date.Second = blockstart[12];
615                                         dprintf("   Date: %02u.%02u.%04u\n", subEntry->data.Date.Day,
616                                                 subEntry->data.Date.Month, subEntry->data.Date.Year);
617                                         dprintf("   Time: %02u:%02u:%02u\n", subEntry->data.Date.Hour,
618                                                 subEntry->data.Date.Minute, subEntry->data.Date.Second);
619                                         subblockcount++;
620                                 }
621                                 break;
622                         case P7110_ENTRYTYPE_LOGO:      /* Caller group logo */
623                                 if (data->Bitmap) {
624                                         data->Bitmap->width = blockstart[5];
625                                         data->Bitmap->height = blockstart[6];
626                                         data->Bitmap->size = (data->Bitmap->width * data->Bitmap->height) / 8;
627                                         memcpy(data->Bitmap->bitmap, blockstart + 10, data->Bitmap->size);
628                                         dprintf("Bitmap\n");
629                                 }
630                                 break;
631                         case P7110_ENTRYTYPE_LOGOSWITCH:/* Logo on/off */
632                                 break;
633                         case P7110_ENTRYTYPE_GROUP:     /* Caller group number */
634                                 if (data->PhonebookEntry) {
635                                         data->PhonebookEntry->Group = blockstart[5] - 1;
636                                         dprintf("   Group: %d\n", data->PhonebookEntry->Group);
637                                 }
638                                 break;
639                         default:
640                                 dprintf("Unknown phonebook block %02x\n", blockstart[0]);
641                                 break;
642                         }
643                         blockstart += blockstart[3];
644                 }
645                 break;
646         case 0x0c:
647                 switch (message[6]) {
648                 case 0x3d: return GE_PHBOOKWRITEFAILED;
649                 case 0x3e: return GE_PHBOOKWRITEFAILED;
650                 default: return GE_NONE;
651                 }
652                 break;  
653         default:
654                 dprintf("Unknown subtype of type 0x03 (%d)\n", message[3]);
655                 return GE_UNKNOWN;
656         }
657         return GE_NONE;
658 }
659
660 /* Just as an example.... */
661 /* But note that both requests are the same type which isn't very 'proper' */ 
662 static GSM_Error P7110_Identify(GSM_Data *data, GSM_Statemachine *state)
663 {
664         unsigned char req[] = {FBUS_FRAME_HEADER, 0x01};
665         unsigned char req2[] = {FBUS_FRAME_HEADER, 0x03, 0x01, 0x32};
666   
667         dprintf("Identifying...\n");
668         PNOK_GetManufacturer(data->Manufacturer);
669         if (SM_SendMessage(state, 4, 0x1b, req) != GE_NONE) return GE_NOTREADY;
670         if (SM_SendMessage(state, 6, 0x1b, req2) != GE_NONE) return GE_NOTREADY;
671         SM_WaitFor(state, data, 0x1b);
672         SM_Block(state, data, 0x1b); /* waits for all requests - returns req2 error */
673         SM_GetError(state, 0x1b);
674         
675         /* Check that we are back at state Initialised */
676         if (SM_Loop(state,0)!=Initialised) return GE_UNKNOWN;
677         return GE_NONE;
678 }
679
680 static GSM_Error P7110_Incoming0x1b(int messagetype, unsigned char *message, int length, GSM_Data *data)
681 {
682         switch (message[3]) {
683         case 02:
684                 if (data->Imei) { 
685                         snprintf(data->Imei, GSM_MAX_IMEI_LENGTH, "%s", message + 4);
686                         dprintf("Received imei %s\n",data->Imei);
687                 }
688                 break;
689         case 04:
690                 if (data->Model) { 
691                         snprintf(data->Model, GSM_MAX_MODEL_LENGTH, "%s", message + 22);
692                         dprintf("Received model %s\n",data->Model);
693                 }
694                 if (data->Revision) { 
695                         snprintf(data->Revision, GSM_MAX_REVISION_LENGTH, "%s", message + 7);
696                         dprintf("Received revision %s\n",data->Revision);
697                 }
698                 break;
699         default:
700                 dprintf("Unknown subtype of type 0x1b (%d)\n", message[3]);
701                 return GE_UNKNOWN;
702         }
703         return GE_NONE;
704 }
705
706
707 /* handle messages of type 0x14 (SMS Handling, Folders, Logos.. */
708 static GSM_Error P7110_IncomingFolder(int messagetype, unsigned char *message, int length, GSM_Data *data)
709 {
710         int i, j;
711         int nextfolder = 0x10;
712         bool found;
713
714         switch (message[3]) {
715         /* getfolders */
716         case 0x7B:
717                 i = 5;
718                 memset(data->SMSFolderList, 0, sizeof(SMS_FolderList));
719                 dprintf("Message: %d SMS Folders received:\n", message[4]);
720
721                 strcpy(data->SMSFolderList->Folder[1].Name, "               ");
722                 data->SMSFolderList->number = message[4];
723       
724                 for (j = 0; j < message[4]; j++) {
725                         int len;
726                         strcpy(data->SMSFolderList->Folder[j].Name, "               ");
727                         data->SMSFolderList->FolderID[j] = message[i];
728                         dprintf("Folder Index: %d", data->SMSFolderList->FolderID[j]);
729                         i += 2;
730                         dprintf("   Folder name: ");
731                         len = 0;
732                         /* search for next folder's index number, i.e. length of folder name */
733                         while (message[i+1] != nextfolder && i < length) {
734                                 i += 2;
735                                 len++;
736                         }
737                         /* see nk7110.txt */
738                         nextfolder += 0x08;
739                         if (nextfolder == 0x28) nextfolder++;
740                         i -= 2 * len +1;
741                         DecodeUnicode(data->SMSFolderList->Folder[j].Name, message + i, len);
742                         dprintf("%s\n", data->SMSFolderList->Folder[j].Name);
743                         i += 2 * len + 2;
744                 }
745                 break;
746
747         /* getfolderstatus */
748         case 0x6C:
749                 memset(data->SMSFolder, 0, sizeof(SMS_Folder));
750                 dprintf("Message: SMS Folder status received: \n" );
751                 data->SMSFolder->FolderID = data->SMSMessage->MemoryType;
752                 data->SMSFolder->number = (message[5] * 256) + message[5];
753                 dprintf("Message: Number of Entries: %i\n" , data->SMSFolder->number);
754                 dprintf("Message: IDs of Entries : ");
755                 for (i = 0; i < message[4] * 256 + message[5]; i++) {
756                         data->SMSFolder->locations[i] = message[6+(i*2)] * 256 + message[(i*2)+7];
757                         dprintf("%d, ", data->SMSFolder->locations[i]);
758                 }
759                 dprintf("\n");
760                 break;
761
762         /* getsms */    
763         case 0x08:
764                 for (i = 0; i < length; i ++)
765                         if (isprint(message[i]))
766                                 dprintf("[%02x%c]", message[i], message[i]);
767                         else
768                                 dprintf("[%02x ]", message[i]);
769                 dprintf("\n");
770
771                 memset(data->SMSMessage, 0, sizeof(GSM_SMSMessage));
772
773                 /* Number of SMS in folder */
774                 data->SMSMessage->Number = message[7]; 
775
776                 /* MessageType/FolderID */
777                 data->SMSMessage->MemoryType = message[5];
778
779                 /* These offsets are 6210/7110 series specific */
780                 /* Short Message status */
781                 data->SMSMessage->Status = message[4];
782                 dprintf("\tStatus: ");
783                 switch (data->SMSMessage->Status) {
784                 case SMS_Read:
785                         dprintf("READ\n");
786                         break;
787                 case SMS_Unread:
788                         dprintf("UNREAD\n");
789                         break;
790                 case SMS_Sent:
791                         dprintf("SENT\n");
792                         break;
793                 case SMS_Unsent:
794                         dprintf("UNSENT\n");
795                         break;
796                 default:
797                         dprintf("UNKNOWN\n");
798                         break;
799                 }
800                 /* See if message# is given back by phone. If not and status is unread */
801                 /* we want it, if status is not unread it's a "random" message given back */
802                 /* by the phone because we want a message of which the # doesn't exist */
803                 found = false;
804                 for (i = 0; i < data->SMSFolder->number; i++) {
805                         if (data->SMSMessage->Number == data->SMSFolder->locations[i]) 
806                                 found = true;
807                 }
808                 if (found==false && data->SMSMessage->Status != SMS_Unread) return GE_INVALIDSMSLOCATION;
809
810                 DecodePDUSMS(message + 6, data->SMSMessage, length);
811
812                 break;
813
814                 /* get list of SMS pictures */
815                 case 0x97:
816                 dprintf("Getting list of SMS pictures...\n");
817                 for (i = 0; i < length; i ++)
818                         if (isprint(message[i]))
819                                 dprintf("[%02x%c]", message[i], message[i]);
820                         else
821                                 dprintf("[%02x ]", message[i]);
822                 dprintf("\n");
823                 break;
824         default:
825
826                 for (i = 0; i < length; i ++)
827                         if (isprint(message[i]))
828                                 dprintf("[%02x%c]", message[i], message[i]);
829                         else
830                                 dprintf("[%02x ]", message[i]);
831                 dprintf("\n");
832                 dprintf("Message: Unknown message of type 14 : %d  length: %d\n", message[3], length);
833                 return GE_UNKNOWN;
834         }
835         return GE_NONE;
836 }
837
838 static GSM_Error P7110_GetSMS(GSM_Data *data, GSM_Statemachine *state)
839 {
840         unsigned char req_folders[] = {FBUS_FRAME_HEADER, 0x7a, 0x00, 0x00};
841         unsigned char req_status[] = {FBUS_FRAME_HEADER, 0x6b, 
842                                 0x08, // Folder ID
843                                 0x0f, 0x01};
844         unsigned char req_sms[] = {FBUS_FRAME_HEADER, 0x07, 
845                                 0x08, // FolderID
846                                 0x00, 
847                                 0x01, // Location
848                                 0x01, 0x65, 0x01};
849         unsigned char req_list[] = {FBUS_FRAME_HEADER, 0x96, 
850                                          0x09, /* location */
851                                          0x0f, 0x07};
852         GSM_Error error;
853
854         /* just testiung picture listing */
855         req_list[4] = data->SMSMessage->MemoryType;
856         if (SM_SendMessage(state, 7, 0x14, req_list) != GE_NONE) return GE_NOTREADY;
857         error = SM_Block(state, data, 0x14);
858
859         /* see if the message we want is from the last read folder, i.e. */
860         /* we don't have to get folder status again */
861         if (data->SMSMessage->MemoryType != data->SMSFolder->FolderID) {
862
863                 dprintf("Getting list of SMS folders...\n");
864                 if (SM_SendMessage(state, 6, 0x14, req_folders) != GE_NONE) return GE_NOTREADY;
865                 error = SM_Block(state, data, 0x14);
866
867                 if (data->SMSMessage->MemoryType > data->SMSFolderList->FolderID[data->SMSFolderList->number-1])
868                         return GE_INVALIDMEMORYTYPE;
869                 data->SMSFolder->FolderID = data->SMSMessage->MemoryType;
870                 req_status[4] = data->SMSMessage->MemoryType;
871
872                 dprintf("Getting entries for SMS folder %i...\n", data->SMSMessage->MemoryType);
873                 if (SM_SendMessage(state, 7, 0x14, req_status) != GE_NONE) return GE_NOTREADY;
874                 error = SM_Block(state, data, 0x14);
875         }
876         
877         dprintf("Getting SMS...\n");
878         req_sms[4] = data->SMSMessage->MemoryType;
879         req_sms[6] = data->SMSMessage->Number;
880         if (SM_SendMessage(state, 10, 0x14, req_sms) != GE_NONE) return GE_NOTREADY;
881         return SM_Block(state, data, 0x14);
882 }
883
884 static GSM_Error P7110_GetPicture(GSM_Data *data, GSM_Statemachine *state)
885 {
886         unsigned char req_list[] = {FBUS_FRAME_HEADER, 0x96, 
887                                          0x09, /* location */
888                                          0x0f, 0x07};
889         if (SM_SendMessage(state, 7, 0x14, req_list) != GE_NONE) return GE_NOTREADY;
890         return SM_Block(state, data, 0x14);
891 }
892
893 #if 0
894 static GSM_Error P7110_GetSMSFolders(GSM_Data *data, GSM_Statemachine *state)
895 {
896         unsigned char req[] = {FBUS_FRAME_HEADER, 0x7A, 0x00, 0x00};
897       
898         dprintf("Getting SMS Folders...\n");
899         if (SM_SendMessage(state, 6, 0x14, req) != GE_NONE) return GE_NOTREADY;
900         return SM_Block(state, data, 0x14);
901 }
902
903 static GSM_Error P7110_GetSMSFolderStatus(GSM_Data *data, GSM_Statemachine *state)
904 {
905         unsigned char req[] = {FBUS_FRAME_HEADER, 0x6B, 
906                                 0x08, // Folder ID
907                                 0x0F, 0x01};
908       
909         req[4] = data->SMSFolder->FolderID;
910         dprintf("Getting SMS Folder Status...\n");
911         if (SM_SendMessage(state, 7, 0x14, req) != GE_NONE) return GE_NOTREADY;
912         return SM_Block(state, data, 0x14);
913 }
914 #endif
915
916 static GSM_Error P7110_SendSMS(GSM_Data *data, GSM_Statemachine *state)
917 {
918         unsigned char req[256] = {FBUS_FRAME_HEADER, 0x01, 0x02, 0x00};
919         int length, i;
920
921         if (data->SMSMessage->MessageCenter.No) {
922                 data->MessageCenter = &data->SMSMessage->MessageCenter;
923                 P7110_GetSMSCenter(data, state);
924         }
925
926         length = EncodePDUSMS(data->SMSMessage, req + 6);
927         if (!length) return GE_SMSWRONGFORMAT;
928         dprintf("Sending SMS...(%d)\n", length);
929         for (i = 0; i < length + 6; i++) {
930                 dprintf("%02x ", req[i]);
931         }
932         dprintf("\n");
933         if (SM_SendMessage(state, length+6, 0x02, req) != GE_NONE) return GE_NOTREADY;
934         return SM_Block(state, data, 0x02);
935 }
936
937 static GSM_Error P7110_IncomingSMS(int messagetype, unsigned char *message, int length, GSM_Data *data)
938 {
939         GSM_Error       e = GE_NONE;
940         int             digits, bytes;
941
942         if (!data) return GE_INTERNALERROR;
943
944         switch (message[3]) {
945         case P7110_SUBSMS_SMSC_RCVD:
946                 dprintf("SMSC Received\n");
947                 /* FIXME: Implement all these in gsm-sms.c */
948                 data->MessageCenter->No = message[4];
949                 data->MessageCenter->Format = message[6];
950                 data->MessageCenter->Validity = message[8];  /* due to changes in format */
951                 digits = message[9];
952                 bytes = message[21] - 1;
953                 
954
955                 sprintf(data->MessageCenter->Name, "%s", message + 33);
956                 
957                 strcpy(data->MessageCenter->Recipient, GetBCDNumber(message+9));
958                 strcpy(data->MessageCenter->Number, GetBCDNumber(message+21));
959                 data->MessageCenter->Type = message[22];
960                 
961                 if (strlen(data->MessageCenter->Recipient) == 0) {
962                         sprintf(data->MessageCenter->Recipient, "(none)");
963                 }
964                 if (strlen(data->MessageCenter->Number) == 0) {
965                         sprintf(data->MessageCenter->Number, "(none)");
966                 }
967                 if(strlen(data->MessageCenter->Name) == 0) {
968                         sprintf(data->MessageCenter->Name, "(none)");
969                 }
970                 
971                 break;
972
973         case P7110_SUBSMS_SMS_SENT:
974                 dprintf("SMS sent\n");
975                 e = GE_SMSSENDOK;
976                 break;
977
978         case P7110_SUBSMS_SEND_FAIL:
979                 dprintf("SMS sending failed\n");
980                 e = GE_SMSSENDFAILED;
981                 break;
982
983         case P7110_SUBSMS_SMS_RCVD:
984         case P7110_SUBSMS_CELLBRD_OK:
985         case P7110_SUBSMS_CELLBRD_FAIL:
986         case P7110_SUBSMS_READ_CELLBRD:
987         case P7110_SUBSMS_SMSC_OK:
988         case P7110_SUBSMS_SMSC_FAIL:
989         case P7110_SUBSMS_SMSC_RCVFAIL:
990                 dprintf("Subtype 0x%02x of type 0x%02x (SMS handling) not implemented\n", message[3], P7110_MSG_SMS);
991                 e = GE_NOTIMPLEMENTED;
992                 break;
993
994         default:
995                 dprintf("Unknown subtype of type 0x%02x (SMS handling): 0x%02x\n", P7110_MSG_SMS, message[3]);
996                 e = GE_UNKNOWN;
997                 break;
998         }
999         return e;
1000 }
1001
1002 static GSM_Error P7110_IncomingClock(int messagetype, unsigned char *message, int length, GSM_Data *data)
1003 {
1004         GSM_Error       e = GE_NONE;
1005
1006         if (!data || !data->DateTime) return GE_INTERNALERROR;  
1007         switch (message[3]) {
1008         case P7110_SUBCLO_DATE_RCVD:
1009                 data->DateTime->Year = (((unsigned int)message[8]) << 8) + message[9];
1010                 data->DateTime->Month = message[10];
1011                 data->DateTime->Day = message[11];
1012                 data->DateTime->Hour = message[12];
1013                 data->DateTime->Minute = message[13];
1014                 data->DateTime->Second = message[14];
1015
1016                 break;
1017         case P7110_SUBCLO_ALARM_RCVD: 
1018                 switch(message[8]) {
1019                 case P7110_ALARM_ENABLED:
1020                         data->DateTime->AlarmEnabled = 1;
1021                         break;
1022                 case P7110_ALARM_DISABLED:
1023                         data->DateTime->AlarmEnabled = 0;
1024                         break;
1025                 default:
1026                         data->DateTime->AlarmEnabled = -1;
1027                         dprintf("Unknown value of alarm enable byte: 0x%02x\n", message[8]);
1028                         e = GE_UNKNOWN;
1029                         break;
1030                 }
1031                 
1032                 data->DateTime->Hour = message[9];
1033                 data->DateTime->Minute = message[10];
1034                 
1035                 break;
1036         default:
1037                 dprintf("Unknown subtype of type 0x%02x (clock handling): 0x%02x\n", P7110_MSG_CLOCK, message[3]);
1038                 e = GE_UNKNOWN;
1039                 break;
1040         }
1041         return e;
1042 }
1043
1044 GSM_Error P7110_GetNoteAlarm(int alarmdiff, GSM_DateTime *time, GSM_DateTime *alarm)
1045 {
1046         time_t                          t_alarm;
1047         struct tm                       tm_time;
1048         struct tm                       *tm_alarm;
1049         GSM_Error                       e = GE_NONE;
1050         
1051         if (!time || !alarm) return GE_INTERNALERROR;
1052         
1053         memset(&tm_time, 0, sizeof(tm_time));
1054         tm_time.tm_year = time->Year - 1900;
1055         tm_time.tm_mon = time->Month - 1;
1056         tm_time.tm_mday = time->Day;
1057         tm_time.tm_hour = time->Hour;
1058         tm_time.tm_min = time->Minute;
1059
1060         tzset();
1061         t_alarm = mktime(&tm_time);
1062         t_alarm -= alarmdiff;
1063         t_alarm += timezone;
1064
1065         tm_alarm = localtime(&t_alarm);
1066
1067         alarm->Year = tm_alarm->tm_year + 1900;
1068         alarm->Month = tm_alarm->tm_mon + 1;
1069         alarm->Day = tm_alarm->tm_mday;
1070         alarm->Hour = tm_alarm->tm_hour;
1071         alarm->Minute = tm_alarm->tm_min;
1072         alarm->Second = tm_alarm->tm_sec;
1073
1074         return e;
1075 }
1076
1077
1078 GSM_Error P7110_GetNoteTimes(unsigned char *block, GSM_CalendarNote *c)
1079 {
1080         time_t          alarmdiff;
1081         GSM_Error       e = GE_NONE;
1082         
1083         if (!c) return GE_INTERNALERROR;
1084
1085         c->Time.Hour = block[0];
1086         c->Time.Minute = block[1];
1087         c->Recurance = ((((unsigned int)block[4]) << 8) + block[5]) * 60;
1088         alarmdiff = (((unsigned int)block[2]) << 8) + block[3];
1089         
1090         if (alarmdiff != 0xffff) {
1091                 P7110_GetNoteAlarm(alarmdiff * 60, &(c->Time), &(c->Alarm));
1092                 c->Alarm.AlarmEnabled = 1;
1093         } else {
1094                 c->Alarm.AlarmEnabled = 0;
1095         }
1096                 
1097         return e;
1098 }
1099
1100 static GSM_Error P7110_IncomingCalendar(int messagetype, unsigned char *message, int length, GSM_Data *data)
1101 {
1102         GSM_Error                       e = GE_NONE;
1103         unsigned char                   *block;
1104         int                             i, alarm, year;
1105         
1106         if (!data || !data->CalendarNote) return GE_INTERNALERROR;
1107
1108         year =  data->CalendarNote->Time.Year;
1109         dprintf("Year: %i\n", data->CalendarNote->Time.Year);
1110         switch (message[3]) {
1111         case P7110_SUBCAL_NOTE_RCVD:
1112                 block = message + 12;
1113                         
1114                 data->CalendarNote->Location = (((unsigned int)message[4]) << 8) + message[5];
1115                 data->CalendarNote->Time.Year = (((unsigned int)message[8]) << 8) + message[9];
1116                 data->CalendarNote->Time.Month = message[10];
1117                 data->CalendarNote->Time.Day = message[11];
1118                 data->CalendarNote->Time.Second = 0;
1119                         
1120                 dprintf("Year: %i\n", data->CalendarNote->Time.Year);
1121                         
1122                 switch (message[6]) {
1123                 case P7110_NOTE_MEETING:
1124                         data->CalendarNote->Type = GCN_MEETING;
1125                         P7110_GetNoteTimes(block, data->CalendarNote);
1126                         DecodeUnicode(data->CalendarNote->Text, (block + 8), block[6]);
1127                         break;
1128                 case P7110_NOTE_CALL:
1129                         data->CalendarNote->Type = GCN_CALL;
1130                         P7110_GetNoteTimes(block, data->CalendarNote);
1131                         DecodeUnicode(data->CalendarNote->Text, (block + 8), block[6]);
1132                         DecodeUnicode(data->CalendarNote->Phone, (block + 8 + block[6] * 2), block[7]);
1133                         break;
1134                 case P7110_NOTE_REMINDER:
1135                         data->CalendarNote->Type = GCN_REMINDER;
1136                         data->CalendarNote->Recurance = ((((unsigned int)block[0]) << 8) + block[1]) * 60;
1137                         DecodeUnicode(data->CalendarNote->Text, (block + 4), block[2]);
1138                         break;
1139                 case P7110_NOTE_BIRTHDAY:
1140                         
1141                         for (i = 0; i < 10; i++) {
1142                                 dprintf("(%i:0x%02x)", i, block[i]);
1143                         }
1144                         dprintf("\n");
1145                         
1146                         data->CalendarNote->Type = GCN_BIRTHDAY;
1147                         data->CalendarNote->Time.Year = year;
1148                         data->CalendarNote->Time.Hour = 23;
1149                         data->CalendarNote->Time.Minute = 59;
1150                         data->CalendarNote->Time.Second = 58;
1151                         
1152                         alarm = ((unsigned int)block[2]) << 24;
1153                         alarm += ((unsigned int)block[3]) << 16;
1154                         alarm += ((unsigned int)block[4]) << 8;
1155                         alarm += block[5];
1156                         
1157                         dprintf("alarm: %i\n", alarm);
1158                         
1159                         if (alarm == 0xffff) {
1160                                 data->CalendarNote->Alarm.AlarmEnabled = 0;
1161                         } else {
1162                                 data->CalendarNote->Alarm.AlarmEnabled = 1;
1163                         }
1164                         
1165                         P7110_GetNoteAlarm(alarm, &(data->CalendarNote->Time), &(data->CalendarNote->Alarm));
1166                         
1167                         data->CalendarNote->Time.Hour = 0;
1168                         data->CalendarNote->Time.Minute = 0;
1169                         data->CalendarNote->Time.Second = 0;
1170                         data->CalendarNote->Time.Year = (((unsigned int)block[6]) << 8) + block[7];
1171                         
1172                         DecodeUnicode(data->CalendarNote->Text, (block + 10), block[9]);
1173                         
1174                         break;
1175                 default:
1176                         data->CalendarNote->Type = -1;
1177                         e = GE_UNKNOWN;
1178                         break;
1179                 }
1180                 
1181                 break;
1182         case P7110_SUBCAL_ADD_MEETING_RESP:
1183         case P7110_SUBCAL_ADD_CALL_RESP:
1184         case P7110_SUBCAL_ADD_BIRTHDAY_RESP:
1185         case P7110_SUBCAL_ADD_REMINDER_RESP:
1186         case P7110_SUBCAL_DEL_NOTE_RESP:
1187         case P7110_SUBCAL_FREEPOS_RCVD:
1188         case P7110_SUBCAL_INFO_RCVD:
1189                 dprintf("Subtype 0x%02x of type 0x%02x (calendar handling) not implemented\n", message[3], P7110_MSG_CALENDAR);
1190                 e = GE_NOTIMPLEMENTED;
1191                 break;
1192         default:
1193                 dprintf("Unknown subtype of type 0x%02x (calendar handling): 0x%02x\n", P7110_MSG_CALENDAR, message[3]);
1194                 e = GE_UNKNOWN;
1195                 break;
1196         }
1197         return e;
1198 }
1199
1200 static int GetMemoryType(GSM_MemoryType memory_type)
1201 {
1202         int result;
1203
1204         switch (memory_type) {
1205         case GMT_MT:
1206                 result = P7110_MEMORY_MT;
1207                 break;
1208         case GMT_ME:
1209                 result = P7110_MEMORY_ME;
1210                 break;
1211         case GMT_SM:
1212                 result = P7110_MEMORY_SM;
1213                 break;
1214         case GMT_FD:
1215                 result = P7110_MEMORY_FD;
1216                 break;
1217         case GMT_ON:
1218                 result = P7110_MEMORY_ON;
1219                 break;
1220         case GMT_EN:
1221                 result = P7110_MEMORY_EN;
1222                 break;
1223         case GMT_DC:
1224                 result = P7110_MEMORY_DC;
1225                 break;
1226         case GMT_RC:
1227                 result = P7110_MEMORY_RC;
1228                 break;
1229         case GMT_MC:
1230                 result = P7110_MEMORY_MC;
1231                 break;
1232         default:
1233                 result = P7110_MEMORY_XX;
1234                 break;
1235         }
1236         return (result);
1237 }
1238
1239 #if 0
1240
1241 static GSM_Error P7110_DialVoice(char *Number)
1242 {
1243
1244   /* Doesn't work (yet) */    /* 3 2 1 5 2 30 35 */
1245
1246         // unsigned char req0[100] = { 0x00, 0x01, 0x64, 0x01 };
1247
1248         unsigned char req[] = {FBUS_FRAME_HEADER, 0x01, 0x01, 0x01, 0x01, 0x05, 0x00, 0x01, 0x03, 0x02, 0x91, 0x00, 0x031, 0x32, 0x00};
1249         // unsigned char req[100]={0x00, 0x01, 0x7c, 0x01, 0x31, 0x37, 0x30, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01};
1250         //  unsigned char req[100] = {FBUS_FRAME_HEADER, 0x01, 0x00, 0x20, 0x01, 0x46};
1251         // unsigned char req_end[] = {0x05, 0x01, 0x01, 0x05, 0x81, 0x01, 0x00, 0x00, 0x01};
1252         int len = 0/*, i*/;
1253
1254         //req[4]=strlen(Number);
1255
1256         //for(i=0; i < strlen(Number) ; i++)
1257         // req[5+i]=Number[i];
1258
1259         //memcpy(req+5+strlen(Number), req_end, 10);
1260
1261         //len=6+strlen(Number);
1262
1263         //len = 4;
1264
1265         
1266         //PGEN_CommandResponse(&link, req0, &len, 0x40, 0x40, 100);
1267         
1268         len=17;
1269
1270         if (PGEN_CommandResponse(&link, req, &len, 0x01, 0x01, 100)==GE_NONE) {
1271                 PGEN_DebugMessage(1, req, len);
1272 //              return GE_NONE;
1273
1274         }
1275 //      } else return GE_NOTIMPLEMENTED;
1276
1277  
1278         while(1){
1279                 link.Loop(NULL);
1280         }
1281
1282         return GE_NOTIMPLEMENTED;
1283 }
1284
1285 #endif
1286
1287 static GSM_Error GetCallerBitmap(GSM_Data *data, GSM_Statemachine *state)
1288 {
1289         unsigned char req[] = {FBUS_FRAME_HEADER, 0x07, 0x01, 0x01, 0x00, 0x01,
1290                                   0x00, 0x10 , /* memory type */
1291                                   0x00, 0x00,  /* location */
1292                                   0x00, 0x00};
1293
1294         req[11] = data->Bitmap->number + 1;
1295         dprintf("Getting caller(%d) logo...\n",data->Bitmap->number);
1296         if (SM_SendMessage(state, 14, 0x03, req)!=GE_NONE) return GE_NOTREADY;
1297         return SM_Block(state, data, 0x03);
1298 }
1299
1300 inline unsigned char PackBlock(u8 id, u8 size, u8 no, u8 *buf, u8 *block)
1301 {
1302         *(block++) = id;
1303         *(block++) = 0;
1304         *(block++) = 0;
1305         *(block++) = size + 6;
1306         *(block++) = no;
1307         memcpy(block, buf, size);
1308         block += size;
1309         *(block++) = 0;
1310         return (size + 6);
1311 }
1312
1313 static GSM_Error SetCallerBitmap(GSM_Data *data, GSM_Statemachine *state)
1314 {
1315         unsigned char req[500] = {FBUS_FRAME_HEADER, 0x0b, 0x00, 0x01, 0x01, 0x00, 0x00, 0x0c,
1316                                   0x00, 0x10,  /* memory type */
1317                                   0x00, 0x00,  /* location */
1318                                   0x00, 0x00, 0x00};
1319         char string[500];
1320         int block, i;
1321         unsigned int count = 18;
1322
1323         if ((data->Bitmap->width!=state->Phone.Info.CallerLogoW) ||
1324             (data->Bitmap->height!=state->Phone.Info.CallerLogoH )) {
1325                 dprintf("Invalid image size - expecting (%dx%d) got (%dx%d)\n",state->Phone.Info.CallerLogoH, state->Phone.Info.CallerLogoW, data->Bitmap->height, data->Bitmap->width); 
1326             return GE_INVALIDIMAGESIZE;
1327         }       
1328
1329         req[13] = data->Bitmap->number + 1;
1330         dprintf("Setting caller(%d) bitmap...\n",data->Bitmap->number);
1331         block = 1;
1332         /* Name */
1333         i = strlen(data->Bitmap->text);
1334         EncodeUnicode((string + 1), data->Bitmap->text, i);
1335         string[0] = i * 2;
1336         count += PackBlock(0x07, i * 2 + 1, block++, string, req + count);
1337         /* Ringtone */
1338         string[0] = data->Bitmap->ringtone;
1339         string[1] = 0;
1340         count += PackBlock(0x0c, 2, block++, string, req + count);
1341         /* Number */
1342         string[0] = data->Bitmap->number+1;
1343         string[1] = 0;
1344         count += PackBlock(0x1e, 2, block++, string, req + count);
1345         /* Logo on/off - assume on for now */
1346         string[0] = 1;
1347         string[1] = 0;
1348         count += PackBlock(0x1c, 2, block++, string, req + count);
1349         /* Logo */
1350         string[0] = data->Bitmap->width;
1351         string[1] = data->Bitmap->height;
1352         string[2] = 0;
1353         string[3] = 0;
1354         string[4] = 0x7e; /* Size */
1355         memcpy(string + 5, data->Bitmap->bitmap, data->Bitmap->size);
1356         count += PackBlock(0x1b, data->Bitmap->size + 5, block++, string, req + count);
1357         req[17] = block - 1;
1358
1359         if (SM_SendMessage(state, count, 0x03, req)!=GE_NONE) return GE_NOTREADY;
1360         return SM_Block(state, data, 0x03);
1361 }
1362
1363 static GSM_Error GetStartupBitmap(GSM_Data *data, GSM_Statemachine *state)
1364 {
1365         unsigned char req[] = {FBUS_FRAME_HEADER, 0xee, 0x15};
1366
1367         dprintf("Getting startup logo...\n");
1368         if (SM_SendMessage(state, 5, 0x7a, req)!=GE_NONE) return GE_NOTREADY;
1369         return SM_Block(state, data, 0x7a);
1370 }
1371
1372 static GSM_Error P7110_IncomingStartup(int messagetype, unsigned char *message, int length, GSM_Data *data)
1373 {
1374         switch (message[3]) {
1375         case 0xeb:
1376                 dprintf("Startup logo set ok\n");
1377                 return GE_NONE;
1378                 break;
1379         case 0xed:
1380                 if (data->Bitmap) {
1381                         /* I'm sure there are blocks here but never mind! */
1382                         data->Bitmap->type = GSM_StartupLogo;
1383                         data->Bitmap->height = message[13];
1384                         data->Bitmap->width = message[17];
1385                         data->Bitmap->size=((data->Bitmap->height/8)+(data->Bitmap->height%8>0))*data->Bitmap->width; /* Can't see this coded anywhere */
1386                         memcpy(data->Bitmap->bitmap, message+22, data->Bitmap->size);
1387                         dprintf("Startup logo got ok - height(%d) width(%d)\n", data->Bitmap->height, data->Bitmap->width);
1388                 }
1389                 return GE_NONE;
1390                 break;
1391         default:
1392                 dprintf("Unknown subtype of type 0x7a (%d)\n", message[3]);
1393                 return GE_UNKNOWN;
1394                 break;
1395         }
1396 }
1397
1398 static GSM_Error GetOperatorBitmap(GSM_Data *data, GSM_Statemachine *state)
1399 {
1400         unsigned char req[] = {FBUS_FRAME_HEADER, 0x70};
1401
1402         dprintf("Getting op logo...\n");
1403         if (SM_SendMessage(state, 4, 0x0a, req) != GE_NONE) return GE_NOTREADY;
1404         return SM_Block(state, data, 0x0a);
1405 }
1406
1407 static GSM_Error SetStartupBitmap(GSM_Data *data, GSM_Statemachine *state)
1408 {
1409         unsigned char req[1000] = {FBUS_FRAME_HEADER, 0xec, 0x15, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x02, 0x00,
1410                                    0x00,           /* Height */
1411                                    0xc0, 0x03, 0x00,
1412                                    0x00,           /* Width */
1413                                    0xc0, 0x04, 0x03, 0x00 };
1414         int count = 21;
1415
1416
1417         if ((data->Bitmap->width!=state->Phone.Info.StartupLogoW) ||
1418             (data->Bitmap->height!=state->Phone.Info.StartupLogoH )) {
1419                 dprintf("Invalid image size - expecting (%dx%d) got (%dx%d)\n",state->Phone.Info.StartupLogoH, state->Phone.Info.StartupLogoW, data->Bitmap->height, data->Bitmap->width); 
1420             return GE_INVALIDIMAGESIZE;
1421         }
1422
1423         req[12] = data->Bitmap->height;
1424         req[16] = data->Bitmap->width;
1425         memcpy(req + count, data->Bitmap->bitmap, data->Bitmap->size);
1426         count += data->Bitmap->size;
1427         dprintf("Setting startup logo...\n");
1428
1429         if (SM_SendMessage(state, count, 0x7a, req) != GE_NONE) return GE_NOTREADY;
1430         return SM_Block(state, data, 0x7a);
1431 }
1432
1433 static GSM_Error SetOperatorBitmap(GSM_Data *data, GSM_Statemachine *state)
1434 {
1435         unsigned char req[500] = { FBUS_FRAME_HEADER, 0xa3, 0x01,
1436                                    0x00,              /* logo enabled */
1437                                    0x00, 0xf0, 0x00,  /* network code (000 00) */
1438                                    0x00 ,0x04,
1439                                    0x08,              /* length of rest */
1440                                    0x00, 0x00,        /* Bitmap width / height */
1441                                    0x00,
1442                                    0x00,              /* Bitmap size */
1443                                    0x00, 0x00
1444         };    
1445         int count = 18;
1446
1447         if ((data->Bitmap->width!=state->Phone.Info.OpLogoW) ||
1448             (data->Bitmap->height!=state->Phone.Info.OpLogoH )) {
1449                 dprintf("Invalid image size - expecting (%dx%d) got (%dx%d)\n",state->Phone.Info.OpLogoH, state->Phone.Info.OpLogoW, data->Bitmap->height, data->Bitmap->width); 
1450             return GE_INVALIDIMAGESIZE;
1451         }
1452
1453         if (strcmp(data->Bitmap->netcode,"000 00")) {  /* set logo */
1454                 req[5] = 0x01;      // Logo enabled
1455                 req[6] = ((data->Bitmap->netcode[1] & 0x0f) << 4) | (data->Bitmap->netcode[0] & 0x0f);
1456                 req[7] = 0xf0 | (data->Bitmap->netcode[2] & 0x0f);
1457                 req[8] = ((data->Bitmap->netcode[5] & 0x0f) << 4) | (data->Bitmap->netcode[4] & 0x0f);
1458                 req[11] = 8 + data->Bitmap->size;
1459                 req[12] = data->Bitmap->width;
1460                 req[13] = data->Bitmap->height;
1461                 req[15] = data->Bitmap->size;
1462                 memcpy(req + count, data->Bitmap->bitmap, data->Bitmap->size);
1463                 count += data->Bitmap->size;
1464         }
1465         dprintf("Setting op logo...\n");
1466         if (SM_SendMessage(state, count, 0x0a, req) != GE_NONE) return GE_NOTREADY;
1467         return SM_Block(state, data, 0x0a);
1468 }
1469
1470 static GSM_Error P7110_GetBitmap(GSM_Data *data, GSM_Statemachine *state)
1471 {
1472         switch(data->Bitmap->type) {
1473         case GSM_CallerLogo:
1474                 return GetCallerBitmap(data, state);
1475         case GSM_StartupLogo:
1476                 return GetStartupBitmap(data, state);
1477         case GSM_OperatorLogo:
1478                 return GetOperatorBitmap(data, state);
1479         default:
1480                 return GE_NOTIMPLEMENTED;
1481         }
1482 }
1483
1484 static GSM_Error P7110_SetBitmap(GSM_Data *data, GSM_Statemachine *state)
1485 {
1486         switch(data->Bitmap->type) {
1487         case GSM_CallerLogo:
1488                 return SetCallerBitmap(data, state);
1489         case GSM_StartupLogo:
1490                 return SetStartupBitmap(data, state);
1491         case GSM_OperatorLogo:
1492                 return SetOperatorBitmap(data, state);
1493         default:
1494                 return GE_NOTIMPLEMENTED;
1495         }
1496 }
1497
1498 static GSM_Error P7110_WritePhonebookLocation(GSM_Data *data, GSM_Statemachine *state)
1499 {
1500         unsigned char req[500] = {FBUS_FRAME_HEADER, 0x0b, 0x00, 0x01, 0x01, 0x00, 0x00, 0x0c,
1501                                   0x00, 0x00,  /* memory type */
1502                                   0x00, 0x00,  /* location */
1503                                   0x00, 0x00, 0x00};
1504         char string[500];
1505         int block, i, j, defaultn;
1506         unsigned int count = 18;
1507         GSM_PhonebookEntry *entry;
1508         
1509         if (data->PhonebookEntry) entry=data->PhonebookEntry;
1510         else return GE_TRYAGAIN;
1511
1512         req[11] = GetMemoryType(entry->MemoryType);
1513         req[12] = (entry->Location >> 8);
1514         req[13] = entry->Location & 0xff;
1515         block = 1;
1516         if (*(entry->Name)) {
1517                 /* Name */
1518                 i = strlen(entry->Name);
1519                 EncodeUnicode((string + 1), entry->Name, i);
1520                 string[0] = i * 2;
1521                 count += PackBlock(0x07, i * 2 + 1, block++, string, req + count);
1522                 /* Group */
1523                 string[0] = entry->Group + 1;
1524                 string[1] = 0;
1525                 count += PackBlock(0x1e, 2, block++, string, req + count);
1526                 /* Default Number */
1527                 defaultn = 999;
1528                 for (i = 0; i < entry->SubEntriesCount; i++)
1529                         if (entry->SubEntries[i].EntryType == GSM_Number)
1530                                 if (!strcmp(entry->Number, entry->SubEntries[i].data.Number))
1531                                         defaultn = i;
1532                 if (defaultn < i) {
1533                         string[0] = entry->SubEntries[defaultn].NumberType;
1534                         string[1] = 0;
1535                         string[2] = 0;
1536                         string[3] = 0;
1537                         i = strlen(entry->SubEntries[defaultn].data.Number);
1538                         EncodeUnicode((string + 5), entry->SubEntries[defaultn].data.Number, i);
1539                         string[4] = i * 2;
1540                         count += PackBlock(0x0b, i * 2 + 5, block++, string, req + count);
1541                 }
1542                 /* Rest of the numbers */
1543                 for (i = 0; i < entry->SubEntriesCount; i++)
1544                         if (entry->SubEntries[i].EntryType == GSM_Number)
1545                                 if (i != defaultn) {
1546                                         string[0] = entry->SubEntries[i].NumberType;
1547                                         string[1] = 0;
1548                                         string[2] = 0;
1549                                         string[3] = 0;
1550                                         j = strlen(entry->SubEntries[i].data.Number);
1551                                         EncodeUnicode((string + 5), entry->SubEntries[i].data.Number, j);
1552                                         string[4] = j + 2;
1553                                         count += PackBlock(0x0b, j * 2 + 5, block++, string, req + count);
1554                                 } 
1555                 req[17] = block - 1;
1556                 dprintf("Writing phonebook entry %s...\n",entry->Name);
1557         }
1558         if (SM_SendMessage(state, count, 0x03, req) != GE_NONE) return GE_NOTREADY;
1559         return SM_Block(state, data, 0x03);
1560 }
1561
1562 static GSM_Error P7110_ReadPhonebookLL(GSM_Data *data, GSM_Statemachine *state, int memtype, int location)
1563 {
1564         GSM_Error       error;
1565         unsigned char   req[2000] = {FBUS_FRAME_HEADER, 0x07, 0x01, 0x01, 0x00, 0x01,
1566                                         0x00, 0x00, /* memory type */ //02,05
1567                                         0x00, 0x00, /* location */
1568                                         0x00, 0x00};
1569
1570         dprintf("Reading phonebook location (%d)\n", location);
1571         
1572         req[9] = memtype;
1573         req[10] = location >> 8;
1574         req[11] = location & 0xff;
1575         
1576         if (SM_SendMessage(state, 14, P7110_MSG_PHONEBOOK, req) != GE_NONE) return GE_NOTREADY;
1577         error = SM_Block(state, data, P7110_MSG_PHONEBOOK);
1578         
1579         return error;
1580 }
1581
1582 static GSM_Error P7110_ReadPhonebook(GSM_Data *data, GSM_Statemachine *state)
1583 {
1584         int memtype, location;
1585         
1586         memtype = GetMemoryType(data->PhonebookEntry->MemoryType);
1587         location = data->PhonebookEntry->Location;
1588         
1589         return P7110_ReadPhonebookLL(data, state, memtype, location);
1590 }
1591
1592 static GSM_Error P7110_GetSpeedDial(GSM_Data *data, GSM_Statemachine *state)
1593 {
1594         int memtype, location;
1595         
1596         memtype = P7110_MEMORY_SPEEDDIALS;
1597         location = data->SpeedDial->Number;
1598         
1599         return P7110_ReadPhonebookLL(data, state, memtype, location);
1600 }
1601
1602 static GSM_Error P7110_GetSMSCenter(GSM_Data *data, GSM_Statemachine *state)
1603 {
1604         GSM_Error       error;
1605         unsigned char   req[] = {FBUS_FRAME_HEADER, P7110_SUBSMS_GET_SMSC, 0x64, 0x00};
1606         
1607         req[5] = data->MessageCenter->No;
1608         
1609         if (SM_SendMessage(state, 6, P7110_MSG_SMS, req) != GE_NONE) return GE_NOTREADY;
1610         error = SM_Block(state, data, P7110_MSG_SMS);
1611         
1612         return error;
1613 }
1614
1615 static GSM_Error P7110_GetClock(char req_type, GSM_Data *data, GSM_Statemachine *state)
1616 {
1617         GSM_Error       error;
1618         unsigned char   req[] = {FBUS_FRAME_HEADER, req_type};
1619         
1620         if (SM_SendMessage(state, 4, P7110_MSG_CLOCK, req) != GE_NONE) return GE_NOTREADY;
1621         error = SM_Block(state, data, P7110_MSG_CLOCK);
1622         
1623         return error;
1624 }
1625
1626 static GSM_Error P7110_GetCalendarNote(GSM_Data *data, GSM_Statemachine *state)
1627 {
1628         GSM_Error       error = GE_NOTREADY;
1629         unsigned char   req[] = {FBUS_FRAME_HEADER, P7110_SUBCAL_GET_NOTE, 0x00, 0x00};
1630         unsigned char   date[] = {FBUS_FRAME_HEADER, P7110_SUBCLO_GET_DATE};
1631         GSM_Data        tmpdata;
1632         GSM_DateTime    tmptime;
1633         
1634         tmpdata.DateTime = &tmptime;
1635         if (SM_SendMessage(state, 4, P7110_MSG_CLOCK, date) == GE_NONE) {
1636                 SM_Block(state, &tmpdata, P7110_MSG_CLOCK);
1637                 req[4] = data->CalendarNote->Location >> 8;
1638                 req[5] = data->CalendarNote->Location & 0xff;
1639                 data->CalendarNote->Time.Year = tmptime.Year;
1640                 
1641                 if(SM_SendMessage(state, 6, P7110_MSG_CALENDAR, req) == GE_NONE) {
1642                         error = SM_Block(state, data, P7110_MSG_CALENDAR);
1643                 }
1644         }       
1645         
1646         return error;
1647 }