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