67fc0f13f8f3d406ab1b61c14ee97426375911de
[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  2001/11/25 21:59:13  short
21   :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001
22
23   Revision 1.27  2001/11/22 17:56:53  pkot
24   smslib update. sms sending
25
26   Revision 1.26  2001/11/19 17:09:59  pkot
27   Bugfixes
28
29   Revision 1.25  2001/11/19 16:24:31  pkot
30   Grrrr... I should have check if I have fixed this typo
31
32   Revision 1.24  2001/11/19 15:53:16  pkot
33   Typos
34
35   Revision 1.23  2001/11/19 13:46:42  pkot
36   reading unread SMS in 6210 from Inbox. Folder updates (Markus Plail)
37
38   Revision 1.22  2001/11/17 20:18:32  pkot
39   Added dau9p connection type for 6210/7110
40
41   Revision 1.21  2001/11/17 16:44:07  pkot
42   Cleanup. Reading SMS for 6100 series. Not that it has some bugs more and does not support UDH yet
43
44   Revision 1.20  2001/11/15 12:15:04  pkot
45   smslib updates. begin work on sms in 6100 series
46
47   Revision 1.19  2001/11/15 12:12:34  pkot
48   7110 and 6110 series phones introduce as Nokia
49
50   Revision 1.18  2001/11/15 12:04:06  pkot
51   Faster initialization for 6100 series (don't check for dlr3 cable)
52
53   Revision 1.17  2001/11/14 10:48:03  pkot
54   6210/7110 debug cleanups
55
56   Revision 1.16  2001/11/13 16:12:21  pkot
57   Preparing libsms to get to work. 6210/7110 SMS and SMS Folder updates
58
59   Revision 1.15  2001/11/08 16:47:48  pkot
60   Start fiddling with 7110 and SMS
61
62   Revision 1.14  2001/09/09 21:45:49  machek
63   Cleanups from Ladislav Michl <ladis@psi.cz>:
64
65   *) do *not* internationalize debug messages
66
67   *) some whitespace fixes, do not use //
68
69   *) break is unneccessary after return
70
71   Revision 1.13  2001/08/16 23:59:32  pkot
72   Fixed (hopefully) timezone mismash (Sheldon Hearn)
73
74   Revision 1.12  2001/08/09 12:34:34  pkot
75   3330 and 6250 support - I have no idea if it does work (mygnokii)
76
77   Revision 1.11  2001/07/05 10:54:53  pkot
78   Solaris 2.7 fixes - should be harmless for other OSes (Michael Wiedmann)
79
80   Revision 1.10  2001/06/27 23:52:49  pkot
81   7110/6210 updates (Marian Jancar)
82
83   Revision 1.9  2001/06/10 23:49:49  pkot
84   Small fixes to hide compilation warnings and allow gnokii.c to compile
85
86   Revision 1.8  2001/05/24 20:47:30  chris
87   More updating of 7110 code and some of xgnokii_lowlevel changed over.
88
89   Revision 1.7  2001/05/07 16:24:04  pkot
90   DLR-3P temporary fix. How should I do it better?
91
92   Revision 1.6  2001/03/23 13:40:24  chris
93   Pavel's patch and a few fixes.
94
95   Revision 1.5  2001/03/22 16:17:06  chris
96   Tidy-ups and fixed gnokii/Makefile and gnokii/ChangeLog which I somehow corrupted.
97
98   Revision 1.4  2001/03/21 23:36:06  chris
99   Added the statemachine
100   This will break gnokii --identify and --monitor except for 6210/7110
101
102   Revision 1.3  2001/03/13 01:24:03  pkot
103   Code cleanup - no warnings during compilation
104
105   Revision 1.2  2001/03/13 01:23:18  pkot
106   Windows updates (Manfred Jonsson)
107
108   Revision 1.1  2001/02/21 19:57:07  chris
109   More fiddling with the directory layout
110
111   Revision 1.1  2001/02/16 14:29:53  chris
112   Restructure of common/.  Fixed a problem in fbus-phonet.c
113   Lots of dprintfs for Marcin
114   Any size xpm can now be loaded (eg for 7110 startup logos)
115   nk7110 code detects 7110/6210 and alters startup logo size to suit
116   Moved Marcin's extended phonebook code into gnokii.c
117
118   Revision 1.7  2001/02/06 21:15:35  chris
119   Preliminary irda support for 7110 etc.  Not well tested!
120
121   Revision 1.6  2001/02/03 23:56:15  chris
122   Start of work on irda support (now we just need fbus-irda.c!)
123   Proper unicode support in 7110 code (from pkot)
124
125   Revision 1.5  2001/02/01 15:17:31  pkot
126   Fixed --identify and added Manfred's manufacturer patch
127
128   Revision 1.4  2001/01/29 17:14:42  chris
129   dprintf now in misc.h (and fiddling with 7110 code)
130
131   Revision 1.3  2001/01/23 15:32:41  chris
132   Pavel's 'break' and 'static' corrections.
133   Work on logos for 7110.
134
135   Revision 1.2  2001/01/17 02:54:54  chris
136   More 7110 work.  Use with care! (eg it is not possible to delete phonebook entries)
137   I can now edit my phonebook in xgnokii but it is 'work in progress'.
138
139   Revision 1.1  2001/01/14 22:46:59  chris
140   Preliminary 7110 support (dlr9 only) and the beginnings of a new structure
141
142 */
143
144 #include <string.h>
145 #include <stdlib.h>
146 #include <ctype.h>
147
148 #define __phones_nk7110_c  /* Turn on prototypes in phones/nk7110.h */
149 #include "misc.h"
150 #include "gsm-common.h"
151 #include "phones/generic.h"
152 #include "phones/nk7110.h"
153 #include "links/fbus.h"
154 #include "links/fbus-phonet.h"
155 #include "phones/nokia.h"
156 #include "gsm-encoding.h"
157
158 #ifdef WIN32
159 #define snprintf _snprintf
160 #endif
161
162 /* Some globals */
163
164 static GSM_IncomingFunctionType P7110_IncomingFunctions[] = {
165         { P7110_MSG_FOLDER,     P7110_IncomingFolder },
166         { P7110_MSG_SMS,        P7110_IncomingSMS },
167         { P7110_MSG_PHONEBOOK,  P7110_IncomingPhonebook },
168         { P7110_MSG_NETSTATUS,  P7110_IncomingNetwork },
169         { P7110_MSG_CALENDAR,   P7110_IncomingCalendar },
170         { P7110_MSG_BATTERY,    P7110_IncomingBattLevel },
171         { P7110_MSG_CLOCK,      P7110_IncomingClock },
172         { P7110_MSG_IDENTITY,   P7110_Incoming0x1b },
173         { P7110_MSG_STLOGO,     P7110_IncomingStartup },
174         { 0, NULL }
175 };
176
177 GSM_Phone phone_nokia_7110 = {
178         P7110_IncomingFunctions,
179         PGEN_IncomingDefault,
180         /* Mobile phone information */
181         {
182                 "7110|6210|6250", /* Supported models */
183                 7,                     /* Max RF Level */
184                 0,                     /* Min RF Level */
185                 GRF_Percentage,        /* RF level units */
186                 7,                     /* Max Battery Level */
187                 0,                     /* Min Battery Level */
188                 GBU_Percentage,        /* Battery level units */
189                 GDT_DateTime,          /* Have date/time support */
190                 GDT_TimeOnly,            /* Alarm supports time only */
191                 1,                     /* Alarms available - FIXME */
192                 60, 96,                /* Startup logo size - 7110 is fixed at init*/
193                 21, 78,                /* Op logo size */
194                 14, 72                 /* Caller logo size */
195         },
196         P7110_Functions
197 };
198
199 /* FIXME - a little macro would help here... */
200
201 static GSM_Error P7110_Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state)
202 {
203         switch (op) {
204         case GOP_Init:
205                 return P7110_Initialise(state);
206         case GOP_GetModel:
207                 return P7110_GetModel(data, state);
208         case GOP_GetRevision:
209                 return P7110_GetRevision(data, state);
210         case GOP_GetImei:
211                 return P7110_GetIMEI(data, state);
212         case GOP_Identify:
213                 return P7110_Identify(data, state);
214         case GOP_GetBatteryLevel:
215                 return P7110_GetBatteryLevel(data, state);
216         case GOP_GetRFLevel:
217                 return P7110_GetRFLevel(data, state);
218         case GOP_GetMemoryStatus:
219                 return P7110_GetMemoryStatus(data, state);
220         case GOP_GetBitmap:
221                 return P7110_GetBitmap(data, state);
222         case GOP_SetBitmap:
223                 return P7110_SetBitmap(data, state);
224         case GOP_ReadPhonebook:
225                 return P7110_ReadPhonebook(data, state);
226         case GOP_WritePhonebook:
227                 return P7110_WritePhonebookLocation(data, state);
228         case GOP_GetNetworkInfo:
229                 return P7110_GetNetworkInfo(data, state);
230         case GOP_GetSpeedDial:
231                 return P7110_GetSpeedDial(data, state);
232         case GOP_GetSMSCenter:
233                 return P7110_GetSMSCenter(data, state);
234         case GOP_GetDateTime:
235                 return P7110_GetClock(P7110_SUBCLO_GET_DATE, data, state);
236         case GOP_GetAlarm:
237                 return P7110_GetClock(P7110_SUBCLO_GET_ALARM, data, state);
238         case GOP_GetCalendarNote:
239                 return P7110_GetCalendarNote(data, state);
240         case GOP_GetSMS:
241                 return P7110_GetSMS(data, state);
242         case GOP_SendSMS:
243                 return P7110_SendSMS(data, state);
244 /* I'm not sure yet if folder functions will be shared or local
245         case GOP_GetSMSFolders:
246                 return P7110_GetSMSFolders(data, state);
247         case GOP_GetSMSFolderStatus:
248         return P7110_GetSMSFolderStatus(data, state);*/
249         default:
250                 return GE_NOTIMPLEMENTED;
251         }
252 }
253
254 /* LinkOK is always true for now... */
255 bool P7110_LinkOK = true;
256
257 /* Initialise is the only function allowed to 'use' state */
258 static GSM_Error P7110_Initialise(GSM_Statemachine *state)
259 {
260         GSM_Data data;
261         char model[10];
262         GSM_Error err;
263         int try = 0, connected = 0;
264
265         /* Copy in the phone info */
266         memcpy(&(state->Phone), &phone_nokia_7110, sizeof(GSM_Phone));
267
268         dprintf("Connecting\n");
269         while (!connected) {
270                 switch (state->Link.ConnectionType) {
271                 case GCT_DAU9P:
272                         if (try == 0) try = 1;
273                 case GCT_Serial:
274                         if (try > 1) return GE_NOTSUPPORTED;
275                         err = FBUS_Initialise(&(state->Link), state, 1 - try);
276                         break;
277                 case GCT_Infrared:
278                 case GCT_Irda:
279                         if (try > 0) return GE_NOTSUPPORTED;
280                         err = PHONET_Initialise(&(state->Link), state);
281                         break;
282                 default:
283                         return GE_NOTSUPPORTED;
284                         break;
285                 }
286
287                 if (err != GE_NONE) {
288                         dprintf("Error in link initialisation: %d\n", err);
289                         try++;
290                         continue;
291                 }
292
293                 SM_Initialise(state);
294
295                 /* Now test the link and get the model */
296                 GSM_DataClear(&data);
297                 data.Model = model;
298                 if (state->Phone.Functions(GOP_GetModel, &data, state) != GE_NONE) try++;
299                 else connected = 1;
300         }
301         /* Check for 7110 and alter the startup logo size */
302         if (strcmp(model, "NSE-5") == 0) {
303                 state->Phone.Info.StartupLogoH = 65;
304                 dprintf("7110 detected - startup logo height set to 65\n");
305         }
306         return GE_NONE;
307 }
308
309 static GSM_Error P7110_GetModel(GSM_Data *data, GSM_Statemachine *state)
310 {
311         unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x01, 0x32};
312   
313         dprintf("Getting model...\n");
314         if (SM_SendMessage(state, 6, 0x1b, req)!=GE_NONE) return GE_NOTREADY;
315         return SM_Block(state, data, 0x1b);
316 }
317
318 static GSM_Error P7110_GetRevision(GSM_Data *data, GSM_Statemachine *state)
319 {
320         unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x01, 0x32};
321   
322         dprintf("Getting revision...\n");
323         if (SM_SendMessage(state, 6, 0x1b, req)!=GE_NONE) return GE_NOTREADY;
324         return SM_Block(state, data, 0x1b);
325 }
326
327 static GSM_Error P7110_GetIMEI(GSM_Data *data, GSM_Statemachine *state)
328 {
329         unsigned char req[] = {FBUS_FRAME_HEADER, 0x01};
330   
331         dprintf("Getting imei...\n");
332         if (SM_SendMessage(state, 4, 0x1b, req)!=GE_NONE) return GE_NOTREADY;
333         return SM_Block(state, data, 0x1b);
334 }
335
336 static GSM_Error P7110_GetBatteryLevel(GSM_Data *data, GSM_Statemachine *state)
337 {
338         unsigned char req[] = {FBUS_FRAME_HEADER, 0x02};
339
340         dprintf("Getting battery level...\n");
341         if (SM_SendMessage(state, 4, 0x17, req) != GE_NONE) return GE_NOTREADY;
342         return SM_Block(state, data, 0x17);
343 }
344
345 static GSM_Error P7110_IncomingBattLevel(int messagetype, unsigned char *message, int length, GSM_Data *data)
346 {
347         switch (message[3]) {
348         case 0x03:
349                 if (data->BatteryLevel) { 
350                         *(data->BatteryUnits) = GBU_Percentage;
351                         *(data->BatteryLevel) = message[5];
352                         dprintf("Battery level %f\n",*(data->BatteryLevel));
353                 }
354                 break;
355         default:
356                 dprintf("Unknown subtype of type 0x17 (%d)\n", message[3]);
357                 return GE_UNKNOWN;
358         }
359         return GE_NONE;
360 }
361
362 static GSM_Error P7110_GetRFLevel(GSM_Data *data, GSM_Statemachine *state)
363 {
364         unsigned char req[] = {FBUS_FRAME_HEADER, 0x81};
365
366         dprintf("Getting rf level...\n");
367         if (SM_SendMessage(state, 4, 0x0a, req) != GE_NONE) return GE_NOTREADY;
368         return SM_Block(state, data, 0x0a);
369 }
370
371 static GSM_Error P7110_GetNetworkInfo(GSM_Data *data, GSM_Statemachine *state)
372 {
373         unsigned char req[] = {FBUS_FRAME_HEADER, 0x70};
374
375         dprintf("Getting Network Info...\n");
376         if (SM_SendMessage(state, 4, 0x0a, req) != GE_NONE) return GE_NOTREADY;
377         return SM_Block(state, data, 0x0a);
378 }
379
380 static GSM_Error P7110_IncomingNetwork(int messagetype, unsigned char *message, int length, GSM_Data *data)
381 {
382         unsigned char *blockstart;
383         int i;
384         
385         switch (message[3]) {
386         case 0x71:
387                 blockstart = message + 6;
388                 for (i = 0; i < message[4]; i++) {
389                         switch (blockstart[0]) {
390                         case 0x01:  /* Operator details */
391                                 /* Network code is stored as 0xBA 0xXC 0xED ("ABC DE"). */
392                                 if (data->NetworkInfo) {
393                                         /* Is this correct? */
394                                         data->NetworkInfo->CellID[0]=blockstart[4];
395                                         data->NetworkInfo->CellID[1]=blockstart[5];
396                                         data->NetworkInfo->LAC[0]=blockstart[6];
397                                         data->NetworkInfo->LAC[1]=blockstart[7];
398                                         data->NetworkInfo->NetworkCode[0] = '0' + (blockstart[8] & 0x0f);
399                                         data->NetworkInfo->NetworkCode[1] = '0' + (blockstart[8] >> 4);
400                                         data->NetworkInfo->NetworkCode[2] = '0' + (blockstart[9] & 0x0f);
401                                         data->NetworkInfo->NetworkCode[3] = ' ';
402                                         data->NetworkInfo->NetworkCode[4] = '0' + (blockstart[10] & 0x0f);
403                                         data->NetworkInfo->NetworkCode[5] = '0' + (blockstart[10] >> 4);
404                                         data->NetworkInfo->NetworkCode[6] = 0;
405                                 }
406                                 if (data->Bitmap) {
407                                         data->Bitmap->netcode[0] = '0' + (blockstart[8] & 0x0f);
408                                         data->Bitmap->netcode[1] = '0' + (blockstart[8] >> 4);
409                                         data->Bitmap->netcode[2] = '0' + (blockstart[9] & 0x0f);
410                                         data->Bitmap->netcode[3] = ' ';
411                                         data->Bitmap->netcode[4] = '0' + (blockstart[10] & 0x0f);
412                                         data->Bitmap->netcode[5] = '0' + (blockstart[10] >> 4);
413                                         data->Bitmap->netcode[6] = 0;
414                                         dprintf("Operator %s ",data->Bitmap->netcode);
415                                 }
416                                 break;
417                         case 0x04: /* Logo */
418                                 if (data->Bitmap) {
419                                         dprintf("Op logo received ok ");
420                                         data->Bitmap->type = GSM_OperatorLogo;
421                                         data->Bitmap->size = blockstart[5]; /* Probably + [4]<<8 */
422                                         data->Bitmap->height = blockstart[3];
423                                         data->Bitmap->width = blockstart[2];
424                                         memcpy(data->Bitmap->bitmap, blockstart + 8, data->Bitmap->size);
425                                         dprintf("Logo (%dx%d) ", data->Bitmap->height, data->Bitmap->width);
426                                 }
427                                 break;
428                         default:
429                                 dprintf("Unknown operator block %d\n", blockstart[0]);
430                                 break;
431                         }
432                         blockstart += blockstart[1];
433                 }
434                 break;
435         case 0x82:
436                 if (data->RFLevel) { 
437                         *(data->RFUnits) = GRF_Percentage;
438                         *(data->RFLevel) = message[4];
439                         dprintf("RF level %f\n",*(data->RFLevel));
440                 }
441                 break;
442         case 0xa4:
443                 dprintf("Op Logo Set OK\n");
444                 break;
445         default:
446                 dprintf("Unknown subtype of type 0x0a (%d)\n", message[3]);
447                 return GE_UNKNOWN;
448         }
449         return GE_NONE;
450 }
451
452 static GSM_Error P7110_GetMemoryStatus(GSM_Data *data, GSM_Statemachine *state)
453 {
454         unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x00, 0x00};
455       
456         dprintf("Getting memory status...\n");
457         req[5] = GetMemoryType(data->MemoryStatus->MemoryType);
458         if (SM_SendMessage(state, 6, 0x03, req) != GE_NONE) return GE_NOTREADY;
459         return SM_Block(state, data, 0x03);
460 }
461
462 static GSM_Error P7110_IncomingPhonebook(int messagetype, unsigned char *message, int length, GSM_Data *data)
463 {
464         unsigned char *blockstart;
465         unsigned char blocks;
466         unsigned char subblockcount;
467         char *str;
468         int i;
469         GSM_SubPhonebookEntry* subEntry = NULL;
470
471         PGEN_DebugMessage(messagetype, message, length);
472
473         switch (message[3]) {
474         case 0x04:  /* Get status response */
475                 if (data->MemoryStatus) {
476                         if (message[5] != 0xff) {
477                                 data->MemoryStatus->Used = (message[16] << 8) + message[17];
478                                 data->MemoryStatus->Free = ((message[14] << 8) + message[15]) - data->MemoryStatus->Used;
479                                 dprintf("Memory status - location = %d\n", (message[8] << 8) + message[9]);
480                         } else {
481                                 dprintf("Unknown error getting mem status\n");
482                                 return GE_NOTIMPLEMENTED;
483                         }
484                 }
485                 break;
486         case 0x08:  /* Read Memory response */
487                 if (data->PhonebookEntry) {
488                         data->PhonebookEntry->Empty = true;
489                         data->PhonebookEntry->Group = 0;
490                         data->PhonebookEntry->Name[0] = '\0';
491                         data->PhonebookEntry->Number[0] = '\0';
492                         data->PhonebookEntry->SubEntriesCount = 0;
493                         data->PhonebookEntry->Date.Year = 0;
494                         data->PhonebookEntry->Date.Month = 0;
495                         data->PhonebookEntry->Date.Day = 0;
496                         data->PhonebookEntry->Date.Hour = 0;
497                         data->PhonebookEntry->Date.Minute = 0;
498                         data->PhonebookEntry->Date.Second = 0;
499                 }
500                 if (message[6] == 0x0f) { // not found
501                         if (message[10] == 0x34 || message[10] == 0x33 || message[10] == 0x30) {
502                                 dprintf("Invalid caller location\n");
503                                 return GE_INVALIDPHBOOKLOCATION;
504                         } else {
505                                 dprintf("Unknown error getting phonebook\n");
506                                 return GE_NOTIMPLEMENTED;
507                         }
508                 }
509                 dprintf("Received phonebook info\n");
510                 blocks     = message[17];        
511                 blockstart = message + 18;
512                 subblockcount = 0;
513            
514                 for (i = 0; i < blocks; i++) {
515                         if (data->PhonebookEntry)
516                                 subEntry = &data->PhonebookEntry->SubEntries[subblockcount];
517                         switch(blockstart[0]) {
518                         case P7110_ENTRYTYPE_POINTER:   /* Pointer */
519                                 switch (message[11]) {  /* Memory type */
520                                 case P7110_MEMORY_SPEEDDIALS:   /* Speed dial numbers */
521                                         if ((data != NULL) && (data->SpeedDial != NULL)) {
522                                                 data->SpeedDial->Location = (((unsigned int)blockstart[6]) << 8) + blockstart[7];
523                                                 switch(blockstart[8]) {
524                                                 case 0x05:
525                                                         data->SpeedDial->MemoryType = GMT_ME;
526                                                         str = "phone";
527                                                         break;
528                                                 case 0x06:
529                                                         str = "SIM";
530                                                         data->SpeedDial->MemoryType = GMT_SM;
531                                                         break;
532                                                 default:
533                                                         str = "unknown";
534                                                         data->SpeedDial->MemoryType = GMT_XX;
535                                                         break;
536                                                 }
537                                         }
538                                         
539                                         dprintf("Speed dial pointer: %i in %s\n", data->SpeedDial->Location, str);
540                                         
541                                         break;
542                                 default:
543                                         /* FIXME: is it possible? */
544                                         dprintf("Wrong memory type(?)\n");
545                                         break;
546                                 }
547                                 
548                                 break;
549                         case P7110_ENTRYTYPE_NAME:      /* Name */
550                                 if (data->Bitmap) {
551                                         DecodeUnicode(data->Bitmap->text, (blockstart + 6), blockstart[5] / 2);
552                                         dprintf("Name: %s\n", data->Bitmap->text);
553                                 } else if (data->PhonebookEntry) {
554                                         DecodeUnicode(data->PhonebookEntry->Name, (blockstart + 6), blockstart[5] / 2);
555                                         data->PhonebookEntry->Empty = false;
556                                         dprintf("   Name: %s\n", data->PhonebookEntry->Name);
557                                 }
558                                 break;
559                         case P7110_ENTRYTYPE_EMAIL:
560                         case P7110_ENTRYTYPE_POSTAL:
561                         case P7110_ENTRYTYPE_NOTE:
562                                 if (data->PhonebookEntry) {
563                                         subEntry->EntryType   = blockstart[0];
564                                         subEntry->NumberType  = 0;
565                                         subEntry->BlockNumber = blockstart[4];
566                                         DecodeUnicode(subEntry->data.Number, (blockstart + 6), blockstart[5] / 2);
567                                         dprintf("   Type: %d (%02x)\n", subEntry->EntryType, subEntry->EntryType);
568                                         dprintf("   Text: %s\n", subEntry->data.Number);
569                                         subblockcount++;
570                                         data->PhonebookEntry->SubEntriesCount++;
571                                 }
572                                 break;
573                         case P7110_ENTRYTYPE_NUMBER:
574                                 if (data->PhonebookEntry) {
575                                         subEntry->EntryType   = blockstart[0];
576                                         subEntry->NumberType  = blockstart[5];
577                                         subEntry->BlockNumber = blockstart[4];
578                                         DecodeUnicode(subEntry->data.Number, (blockstart + 10), blockstart[9] / 2);
579                                         if (!subblockcount) strcpy(data->PhonebookEntry->Number, subEntry->data.Number);
580                                         dprintf("   Type: %d (%02x)\n", subEntry->NumberType, subEntry->NumberType);
581                                         dprintf(" Number: %s\n", subEntry->data.Number);                                        
582                                         subblockcount++;
583                                         data->PhonebookEntry->SubEntriesCount++;
584                                 }
585                                 break;
586                         case P7110_ENTRYTYPE_RINGTONE:  /* Ringtone */
587                                 if (data->Bitmap) {
588                                         data->Bitmap->ringtone = blockstart[5];
589                                         dprintf("Ringtone no. %d\n", data->Bitmap->ringtone);
590                                 }
591                                 break;
592                         case P7110_ENTRYTYPE_DATE:
593                                 if (data->PhonebookEntry) {
594                                         subEntry->EntryType=blockstart[0];
595                                         subEntry->NumberType=blockstart[5];
596                                         subEntry->BlockNumber=blockstart[4];
597                                         subEntry->data.Date.Year=(blockstart[6] << 8) + blockstart[7];
598                                         subEntry->data.Date.Month  = blockstart[8];
599                                         subEntry->data.Date.Day    = blockstart[9];
600                                         subEntry->data.Date.Hour   = blockstart[10];
601                                         subEntry->data.Date.Minute = blockstart[11];
602                                         subEntry->data.Date.Second = blockstart[12];
603                                         dprintf("   Date: %02u.%02u.%04u\n", subEntry->data.Date.Day,
604                                                 subEntry->data.Date.Month, subEntry->data.Date.Year);
605                                         dprintf("   Time: %02u:%02u:%02u\n", subEntry->data.Date.Hour,
606                                                 subEntry->data.Date.Minute, subEntry->data.Date.Second);
607                                         subblockcount++;
608                                 }
609                                 break;
610                         case P7110_ENTRYTYPE_LOGO:      /* Caller group logo */
611                                 if (data->Bitmap) {
612                                         data->Bitmap->width = blockstart[5];
613                                         data->Bitmap->height = blockstart[6];
614                                         data->Bitmap->size = (data->Bitmap->width * data->Bitmap->height) / 8;
615                                         memcpy(data->Bitmap->bitmap, blockstart + 10, data->Bitmap->size);
616                                         dprintf("Bitmap\n");
617                                 }
618                                 break;
619                         case P7110_ENTRYTYPE_LOGOSWITCH:/* Logo on/off */
620                                 break;
621                         case P7110_ENTRYTYPE_GROUP:     /* Caller group number */
622                                 if (data->PhonebookEntry) {
623                                         data->PhonebookEntry->Group = blockstart[5] - 1;
624                                         dprintf("   Group: %d\n", data->PhonebookEntry->Group);
625                                 }
626                                 break;
627                         default:
628                                 dprintf("Unknown phonebook block %02x\n", blockstart[0]);
629                                 break;
630                         }
631                         blockstart += blockstart[3];
632                 }
633                 break;
634         case 0x0c:
635                 switch (message[6]) {
636                 case 0x3d: return GE_PHBOOKWRITEFAILED;
637                 case 0x3e: return GE_PHBOOKWRITEFAILED;
638                 default: return GE_NONE;
639                 }
640                 break;  
641         default:
642                 dprintf("Unknown subtype of type 0x03 (%d)\n", message[3]);
643                 return GE_UNKNOWN;
644         }
645         return GE_NONE;
646 }
647
648 /* Just as an example.... */
649 /* But note that both requests are the same type which isn't very 'proper' */ 
650 static GSM_Error P7110_Identify(GSM_Data *data, GSM_Statemachine *state)
651 {
652         unsigned char req[] = {FBUS_FRAME_HEADER, 0x01};
653         unsigned char req2[] = {FBUS_FRAME_HEADER, 0x03, 0x01, 0x32};
654   
655         dprintf("Identifying...\n");
656         PNOK_GetManufacturer(data->Manufacturer);
657         if (SM_SendMessage(state, 4, 0x1b, req) != GE_NONE) return GE_NOTREADY;
658         if (SM_SendMessage(state, 6, 0x1b, req2) != GE_NONE) return GE_NOTREADY;
659         SM_WaitFor(state, data, 0x1b);
660         SM_Block(state, data, 0x1b); /* waits for all requests - returns req2 error */
661         SM_GetError(state, 0x1b);
662         
663         /* Check that we are back at state Initialised */
664         if (SM_Loop(state,0)!=Initialised) return GE_UNKNOWN;
665         return GE_NONE;
666 }
667
668 static GSM_Error P7110_Incoming0x1b(int messagetype, unsigned char *message, int length, GSM_Data *data)
669 {
670         switch (message[3]) {
671         case 02:
672                 if (data->Imei) { 
673                         snprintf(data->Imei, GSM_MAX_IMEI_LENGTH, "%s", message + 4);
674                         dprintf("Received imei %s\n",data->Imei);
675                 }
676                 break;
677         case 04:
678                 if (data->Model) { 
679                         snprintf(data->Model, GSM_MAX_MODEL_LENGTH, "%s", message + 22);
680                         dprintf("Received model %s\n",data->Model);
681                 }
682                 if (data->Revision) { 
683                         snprintf(data->Revision, GSM_MAX_REVISION_LENGTH, "%s", message + 7);
684                         dprintf("Received revision %s\n",data->Revision);
685                 }
686                 break;
687         default:
688                 dprintf("Unknown subtype of type 0x1b (%d)\n", message[3]);
689                 return GE_UNKNOWN;
690         }
691         return GE_NONE;
692 }
693
694
695 /* handle messages of type 0x14 (SMS Handling, Folders, Logos.. */
696 static GSM_Error P7110_IncomingFolder(int messagetype, unsigned char *message, int length, GSM_Data *data)
697 {
698         int i, j;
699         int nextfolder = 0x10;
700         bool found;
701
702         switch (message[3]) {
703         /* getfolders */
704         case 0x7B:
705                 i = 5;
706                 memset(data->SMSFolderList, 0, sizeof(SMS_FolderList));
707                 dprintf("Message: %d SMS Folders received:\n", message[4]);
708
709                 strcpy(data->SMSFolderList->Folder[1].Name, "               ");
710                 data->SMSFolderList->number = message[4];
711       
712                 for (j = 0; j < message[4]; j++) {
713                         int len;
714                         strcpy(data->SMSFolderList->Folder[j].Name, "               ");
715                         data->SMSFolderList->FolderID[j] = message[i];
716                         dprintf("Folder Index: %d", data->SMSFolderList->FolderID[j]);
717                         i += 2;
718                         dprintf("   Folder name: ");
719                         len = 0;
720                         /* search for next folder's index number, i.e. length of folder name */
721                         while (message[i+1] != nextfolder && i < length) {
722                                 i += 2;
723                                 len++;
724                         }
725                         /* see nk7110.txt */
726                         nextfolder += 0x08;
727                         if (nextfolder == 0x28) nextfolder++;
728                         i -= 2 * len +1;
729                         DecodeUnicode(data->SMSFolderList->Folder[j].Name, message + i, len);
730                         dprintf("%s\n", data->SMSFolderList->Folder[j].Name);
731                         i += 2 * len + 2;
732                 }
733                 break;
734
735         /* getfolderstatus */
736         case 0x6C:
737                 memset(data->SMSFolder, 0, sizeof(SMS_Folder));
738                 dprintf("Message: SMS Folder status received: \n" );
739                 data->SMSFolder->FolderID = data->SMSMessage->MemoryType;
740                 data->SMSFolder->number = (message[5] * 256) + message[5];
741                 dprintf("Message: Number of Entries: %i\n" , data->SMSFolder->number);
742                 dprintf("Message: IDs of Entries : ");
743                 for (i = 0; i < message[4] * 256 + message[5]; i++) {
744                         data->SMSFolder->locations[i] = message[6+(i*2)] * 256 + message[(i*2)+7];
745                         dprintf("%d, ", data->SMSFolder->locations[i]);
746                 }
747                 dprintf("\n");
748                 break;
749
750         /* getsms */    
751         case 0x08:
752                 for (i = 0; i < length; i ++)
753                         if (isprint(message[i]))
754                                 dprintf("[%02x%c]", message[i], message[i]);
755                         else
756                                 dprintf("[%02x ]", message[i]);
757                 dprintf("\n");
758
759                 memset(data->SMSMessage, 0, sizeof(GSM_SMSMessage));
760
761                 /* Number of SMS in folder */
762                 data->SMSMessage->Number = message[7]; 
763
764                 /* MessageType/FolderID */
765                 data->SMSMessage->MemoryType = message[5];
766
767                 /* These offsets are 6210/7110 series specific */
768                 /* Short Message status */
769                 data->SMSMessage->Status = message[4];
770                 dprintf("\tStatus: ");
771                 switch (data->SMSMessage->Status) {
772                 case SMS_Read:
773                         dprintf("READ\n");
774                         break;
775                 case SMS_Unread:
776                         dprintf("UNREAD\n");
777                         break;
778                 case SMS_Sent:
779                         dprintf("SENT\n");
780                         break;
781                 case SMS_Unsent:
782                         dprintf("UNSENT\n");
783                         break;
784                 default:
785                         dprintf("UNKNOWN\n");
786                         break;
787                 }
788                 /* See if message# is given back by phone. If not and status is unread */
789                 /* we want it, if status is not unread it's a "random" message given back */
790                 /* by the phone because we want a message of which the # doesn't exist */
791                 found = false;
792                 for (i = 0; i < data->SMSFolder->number; i++) {
793                         if (data->SMSMessage->Number == data->SMSFolder->locations[i]) 
794                                 found = true;
795                 }
796                 if (found==false && data->SMSMessage->Status != SMS_Unread) return GE_INVALIDSMSLOCATION;
797
798                 DecodePDUSMS(message + 6, data->SMSMessage, length);
799
800                 break;
801
802                 /* get list of SMS pictures */
803                 case 0x97:
804                 dprintf("Getting list of SMS pictures...\n");
805                 for (i = 0; i < length; i ++)
806                         if (isprint(message[i]))
807                                 dprintf("[%02x%c]", message[i], message[i]);
808                         else
809                                 dprintf("[%02x ]", message[i]);
810                 dprintf("\n");
811                 break;
812         default:
813
814                 for (i = 0; i < length; i ++)
815                         if (isprint(message[i]))
816                                 dprintf("[%02x%c]", message[i], message[i]);
817                         else
818                                 dprintf("[%02x ]", message[i]);
819                 dprintf("\n");
820                 dprintf("Message: Unknown message of type 14 : %d  length: %d\n", message[3], length);
821                 return GE_UNKNOWN;
822         }
823         return GE_NONE;
824 }
825
826 static GSM_Error P7110_GetSMS(GSM_Data *data, GSM_Statemachine *state)
827 {
828         unsigned char req_folders[] = {FBUS_FRAME_HEADER, 0x7a, 0x00, 0x00};
829         unsigned char req_status[] = {FBUS_FRAME_HEADER, 0x6b, 
830                                 0x08, // Folder ID
831                                 0x0f, 0x01};
832         unsigned char req_sms[] = {FBUS_FRAME_HEADER, 0x07, 
833                                 0x08, // FolderID
834                                 0x00, 
835                                 0x01, // Location
836                                 0x01, 0x65, 0x01};
837         unsigned char req_list[] = {FBUS_FRAME_HEADER, 0x96, 
838                                          0x09, /* location */
839                                          0x0f, 0x07};
840         GSM_Error error;
841
842         /* just testiung picture listing */
843         req_list[4] = data->SMSMessage->MemoryType;
844         if (SM_SendMessage(state, 7, 0x14, req_list) != GE_NONE) return GE_NOTREADY;
845         error = SM_Block(state, data, 0x14);
846
847         /* see if the message we want is from the last read folder, i.e. */
848         /* we don't have to get folder status again */
849         if (data->SMSMessage->MemoryType != data->SMSFolder->FolderID) {
850
851                 dprintf("Getting list of SMS folders...\n");
852                 if (SM_SendMessage(state, 6, 0x14, req_folders) != GE_NONE) return GE_NOTREADY;
853                 error = SM_Block(state, data, 0x14);
854
855                 if (data->SMSMessage->MemoryType > data->SMSFolderList->FolderID[data->SMSFolderList->number-1])
856                         return GE_INVALIDMEMORYTYPE;
857                 data->SMSFolder->FolderID = data->SMSMessage->MemoryType;
858                 req_status[4] = data->SMSMessage->MemoryType;
859
860                 dprintf("Getting entries for SMS folder %i...\n", data->SMSMessage->MemoryType);
861                 if (SM_SendMessage(state, 7, 0x14, req_status) != GE_NONE) return GE_NOTREADY;
862                 error = SM_Block(state, data, 0x14);
863         }
864         
865         dprintf("Getting SMS...\n");
866         req_sms[4] = data->SMSMessage->MemoryType;
867         req_sms[6] = data->SMSMessage->Number;
868         if (SM_SendMessage(state, 10, 0x14, req_sms) != GE_NONE) return GE_NOTREADY;
869         return SM_Block(state, data, 0x14);
870 }
871
872 static GSM_Error P7110_GetPicture(GSM_Data *data, GSM_Statemachine *state)
873 {
874         unsigned char req_list[] = {FBUS_FRAME_HEADER, 0x96, 
875                                          0x09, /* location */
876                                          0x0f, 0x07};
877         if (SM_SendMessage(state, 7, 0x14, req_list) != GE_NONE) return GE_NOTREADY;
878         return SM_Block(state, data, 0x14);
879 }
880
881 #if 0
882 static GSM_Error P7110_GetSMSFolders(GSM_Data *data, GSM_Statemachine *state)
883 {
884         unsigned char req[] = {FBUS_FRAME_HEADER, 0x7A, 0x00, 0x00};
885       
886         dprintf("Getting SMS Folders...\n");
887         if (SM_SendMessage(state, 6, 0x14, req) != GE_NONE) return GE_NOTREADY;
888         return SM_Block(state, data, 0x14);
889 }
890
891 static GSM_Error P7110_GetSMSFolderStatus(GSM_Data *data, GSM_Statemachine *state)
892 {
893         unsigned char req[] = {FBUS_FRAME_HEADER, 0x6B, 
894                                 0x08, // Folder ID
895                                 0x0F, 0x01};
896       
897         req[4] = data->SMSFolder->FolderID;
898         dprintf("Getting SMS Folder Status...\n");
899         if (SM_SendMessage(state, 7, 0x14, req) != GE_NONE) return GE_NOTREADY;
900         return SM_Block(state, data, 0x14);
901 }
902 #endif
903
904 static GSM_Error P7110_SendSMS(GSM_Data *data, GSM_Statemachine *state)
905 {
906         unsigned char req[256] = {FBUS_FRAME_HEADER, 0x01, 0x02, 0x00};
907         unsigned char smsc_req[] = {FBUS_FRAME_HEADER, 0x33, 0x64, 0x00};
908         int length, i;
909
910         if (data->SMSMessage->MessageCenter.No) {
911                 data->MessageCenter = &data->SMSMessage->MessageCenter;
912                 P7110_GetSMSCenter(data, state);
913 //              SM_SendMessage(state, 6, 0x02, smsc_req);
914 //              SM_Block(state, data, 0x02);
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, i;
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 }