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