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