This commit was generated by cvs2svn to compensate for changes in r161,
[gnokii.git] / xgnokii / xgnokii_lowlevel.c
1 /*
2
3   $Id$
4   
5   X G N O K I I
6
7   A Linux/Unix GUI for Nokia mobile phones.
8   Copyright (C) 1999 Pavel Janík ml., Hugh Blemings
9   & Ján Derfiòák <ja@mail.upjs.sk>.
10
11   Released under the terms of the GNU GPL, see file COPYING for more details.
12
13   $Log$
14   Revision 1.1.1.4  2002/04/03 00:08:33  short
15   Found in "gnokii-working" directory, some November-patches version
16
17   Revision 1.19  2001/09/14 13:09:26  pkot
18   Xgnokii calendar updates
19
20   Revision 1.18  2001/06/20 21:27:36  pkot
21   IrDA patch (Martin Jancar)
22
23   Revision 1.17  2001/06/10 11:40:06  machek
24   xgnokii converted to new structure w.r.t. SMS messages.
25
26   Revision 1.16  2001/05/24 20:47:31  chris
27   More updating of 7110 code and some of xgnokii_lowlevel changed over.
28
29   Revision 1.15  2001/03/23 08:24:57  ja
30   New preview for 6210 in xgnokii's logos module.
31
32   Revision 1.14  2001/03/21 23:36:09  chris
33   Added the statemachine
34   This will break gnokii --identify and --monitor except for 6210/7110
35
36   Revision 1.13  2001/03/05 10:42:03  ja
37   Pavel Machek's vcard and finegrained indicators patch.
38
39   Revision 1.12  2001/02/02 08:09:57  ja
40   New dialogs for 6210/7110 in xgnokii. Fixed the smsd for new capabilty code.
41
42   Revision 1.11  2001/01/29 15:22:20  machek
43   Use integer as bitfield instead of struct of int:1.
44
45   Be able to read phonebook saved in gnokii format from xgnokii.
46
47   Revision 1.10  2001/01/17 02:54:56  chris
48   More 7110 work.  Use with care! (eg it is not possible to delete phonebook entries)
49   I can now edit my phonebook in xgnokii but it is 'work in progress'.
50
51   Revision 1.9  2001/01/15 21:10:20  ja
52   Better status reporting in xgnokii, fixed phone capabilities detection in xgnokii.
53
54   
55 */
56
57 #include <unistd.h>
58 #include <pthread.h>
59 #include <string.h>
60 #include <glib.h>
61 #include "misc.h"
62 #include "gsm-common.h"
63 #include "gsm-api.h"
64 #include "fbus-6110.h"
65 #include "fbus-3810.h"
66 #include "xgnokii_lowlevel.h"
67 #include "xgnokii.h"
68 #include "gsm-statemachine.h"
69 //#include "xgnokii_common.h"
70
71 pthread_t monitor_th;
72 PhoneMonitor phoneMonitor;
73 pthread_mutex_t memoryMutex;
74 pthread_cond_t  memoryCond;
75 pthread_mutex_t calendarMutex;
76 pthread_cond_t  calendarCond;
77 pthread_mutex_t smsMutex;
78 pthread_mutex_t sendSMSMutex;
79 pthread_cond_t  sendSMSCond;
80 pthread_mutex_t saveSMSMutex;
81 pthread_cond_t  saveSMSCond;
82 pthread_mutex_t callMutex;
83 pthread_mutex_t netMonMutex;
84 pthread_mutex_t speedDialMutex;
85 pthread_cond_t  speedDialCond;
86 pthread_mutex_t callerGroupMutex;
87 pthread_cond_t  callerGroupCond;
88 pthread_mutex_t smsCenterMutex;  
89 pthread_cond_t  smsCenterCond;
90 pthread_mutex_t alarmMutex;  
91 pthread_cond_t  alarmCond;
92 pthread_mutex_t getBitmapMutex;
93 pthread_cond_t  getBitmapCond;
94 pthread_mutex_t setBitmapMutex;
95 pthread_cond_t  setBitmapCond;
96 pthread_mutex_t getNetworkInfoMutex;
97 pthread_cond_t  getNetworkInfoCond;
98 static pthread_mutex_t eventsMutex;
99 static GSList *ScheduledEvents = NULL;
100
101 /* This symbol must be export as it is (mis)used by xgnokii_logos.c
102  */
103 GSM_Statemachine xgnokii_statemachine;
104
105
106 inline void GUI_InsertEvent (PhoneEvent *event)
107 {
108 # ifdef XDEBUG
109   g_print ("Inserting Event: %d\n", event->event);
110 # endif
111   pthread_mutex_lock (&eventsMutex);
112   ScheduledEvents = g_slist_prepend (ScheduledEvents, event);
113   pthread_mutex_unlock (&eventsMutex);
114 }
115
116
117 inline static PhoneEvent *RemoveEvent (void)
118 {
119   GSList *list;
120   PhoneEvent *event = NULL;
121
122   pthread_mutex_lock (&eventsMutex);
123   list = g_slist_last (ScheduledEvents);
124   if (list)
125   {
126     event = (PhoneEvent *) list->data;
127     ScheduledEvents = g_slist_remove_link (ScheduledEvents, list);
128     g_slist_free_1 (list);
129   }
130   pthread_mutex_unlock (&eventsMutex);
131
132   return (event);
133 }
134
135
136 static void InitModelInf (void)
137 {
138   gchar buf[64];
139   GSM_Error error;
140   register gint i = 0;
141   GSM_Data data;
142
143   GSM_DataClear(&data);
144   data.Model=buf;
145   while ((error = SM_Functions(GOP_GetModel,&data,&xgnokii_statemachine)) != GE_NONE && i++ < 15)
146     sleep(1);
147
148   if (error == GE_NONE)
149   {
150     g_free (phoneMonitor.phone.model);
151     phoneMonitor.phone.version = g_strdup (buf);
152     phoneMonitor.phone.model = GetModel (buf);
153     if (phoneMonitor.phone.model == NULL)
154       phoneMonitor.phone.model = g_strdup (_("unknown"));
155
156     phoneMonitor.supported = GetPhoneModel(buf)->flags;
157   }
158
159   i = 0;
160   data.Revision=buf;
161   while ((error = SM_Functions(GOP_GetRevision,&data,&xgnokii_statemachine)) != GE_NONE && i++ < 5)
162     sleep(1);
163
164   if (error == GE_NONE)
165   {
166     g_free (phoneMonitor.phone.revision);
167     phoneMonitor.phone.revision = g_strdup (buf);
168   }
169
170   i = 0;
171   data.Imei=buf;
172   while ((error = SM_Functions(GOP_GetImei,&data,&xgnokii_statemachine)) != GE_NONE && i++ < 5)
173     sleep(1);
174
175   if (error == GE_NONE)
176   {
177     g_free (phoneMonitor.phone.imei);
178     phoneMonitor.phone.imei = g_strdup (buf);
179   }
180
181
182 #ifdef XDEBUG
183   g_print ("Version: %s\n", phoneMonitor.phone.version);
184   g_print ("Model: %s\n", phoneMonitor.phone.model);
185   g_print ("IMEI: %s\n", phoneMonitor.phone.imei);
186   g_print ("Revision: %s\n", phoneMonitor.phone.revision);
187 #endif
188 }
189
190
191 static GSM_Error fbusinit(bool enable_monitoring)
192 {
193   int count=0;
194   GSM_Error error=GE_NOLINK;
195   GSM_ConnectionType connection=GCT_Serial;
196
197   if (!strcmp(xgnokiiConfig.connection, "infrared"))
198     connection = GCT_Infrared;
199
200   if (!strcmp(xgnokiiConfig.connection, "irda"))
201     connection = GCT_Irda;
202
203   /* Initialise the code for the GSM interface. */     
204
205   if (error == GE_NOLINK)
206     error = GSM_Initialise (xgnokiiConfig.model, xgnokiiConfig.port,
207                             xgnokiiConfig.initlength, connection, NULL /*RLP_DisplayF96Frame*/, &xgnokii_statemachine);
208
209 #ifdef XDEBUG
210   g_print ("fbusinit: error %d\n", error);
211 #endif
212
213   if (error != GE_NONE) {
214     g_print (_("GSM/FBUS init failed! (Unknown model ?). Quitting.\n"));
215     /* FIXME: should popup some message... */
216     return (error);
217   }
218
219   while (count++ < 40 && *GSM_LinkOK == false)
220     usleep(50000);
221 #ifdef XDEBUG
222   g_print("After usleep. GSM_LinkOK: %d\n", *GSM_LinkOK);
223 #endif
224
225   if (*GSM_LinkOK != true) {
226     return (GE_NOLINK);
227   }
228
229   InitModelInf ();
230   return(GE_NONE);
231 }
232
233
234 void GUI_InitPhoneMonitor (void)
235 {
236   phoneMonitor.phone.model = g_strdup (_("unknown"));
237   phoneMonitor.phone.version = phoneMonitor.phone.model;
238   phoneMonitor.phone.revision = g_strdup (_("unknown"));
239   phoneMonitor.phone.imei = g_strdup (_("unknown"));
240   phoneMonitor.supported = 0;
241   phoneMonitor.rfLevel = phoneMonitor.batteryLevel = -1;
242   phoneMonitor.powerSource = GPS_BATTERY;
243   phoneMonitor.working = NULL;
244   phoneMonitor.alarm = FALSE;
245   phoneMonitor.sms.unRead = phoneMonitor.sms.used = phoneMonitor.sms.slots = 0;
246   phoneMonitor.sms.messages = NULL;
247   phoneMonitor.call.callInProgress = CS_Idle;
248   *phoneMonitor.call.callNum = '\0';
249   phoneMonitor.netmonitor.number = 0;
250   *phoneMonitor.netmonitor.screen = *phoneMonitor.netmonitor.screen3 = 
251   *phoneMonitor.netmonitor.screen4 = *phoneMonitor.netmonitor.screen5 = '\0';
252   pthread_mutex_init (&memoryMutex, NULL);
253   pthread_cond_init (&memoryCond, NULL);
254   pthread_mutex_init (&calendarMutex, NULL);
255   pthread_cond_init (&calendarCond, NULL);
256   pthread_mutex_init (&smsMutex, NULL);
257   pthread_mutex_init (&sendSMSMutex, NULL);
258   pthread_cond_init (&sendSMSCond, NULL);
259   pthread_mutex_init (&saveSMSMutex, NULL);
260   pthread_cond_init (&saveSMSCond, NULL);
261   pthread_mutex_init (&callMutex, NULL);
262   pthread_mutex_init (&eventsMutex, NULL);
263   pthread_mutex_init (&callMutex, NULL);
264   pthread_mutex_init (&netMonMutex, NULL);
265   pthread_mutex_init (&speedDialMutex, NULL);
266   pthread_cond_init (&speedDialCond, NULL);
267   pthread_mutex_init (&callerGroupMutex, NULL);
268   pthread_cond_init (&callerGroupCond, NULL);
269   pthread_mutex_init (&smsCenterMutex, NULL);
270   pthread_cond_init (&smsCenterCond, NULL);
271   pthread_mutex_init (&getBitmapMutex, NULL);
272   pthread_cond_init (&getBitmapCond, NULL);
273   pthread_mutex_init (&setBitmapMutex, NULL);
274   pthread_cond_init (&setBitmapCond, NULL);
275   pthread_mutex_init (&getNetworkInfoMutex, NULL);
276   pthread_cond_init (&getNetworkInfoCond, NULL);
277 }
278
279
280 static inline void FreeElement (gpointer data, gpointer userData)
281 {
282   g_free ((GSM_SMSMessage *) data);
283 }
284
285
286 static inline void FreeArray (GSList **array)
287 {
288   if (*array)
289   {
290     g_slist_foreach (*array, FreeElement, NULL);
291     g_slist_free (*array);
292     *array = NULL;
293   }
294 }
295
296
297 static void RefreshSMS (const gint slots)
298 {
299   GSM_Error error;
300   GSM_SMSMessage *msg;
301   register gint i;
302   gint unread = 0;
303
304 # ifdef XDEBUG
305   g_print ("RefreshSMS is running...\n");
306 # endif
307
308   pthread_mutex_lock (&smsMutex);
309   FreeArray (&(phoneMonitor.sms.messages));
310   phoneMonitor.sms.used = 0;
311   pthread_mutex_unlock (&smsMutex);
312
313   for (i=1; i<=slots; i++)
314   {
315     GSM_Data gdat;
316     GSM_DataClear(&gdat);
317     msg = g_malloc (sizeof (GSM_SMSMessage));
318     msg->MemoryType = GMT_SM;
319     msg->Location = i;
320     gdat.SMSMessage = msg;
321
322     if ((error = SM_Functions(GOP_GetSMS, &gdat, &xgnokii_statemachine)) == GE_NONE)
323     {
324       pthread_mutex_lock (&smsMutex);
325       phoneMonitor.sms.messages = g_slist_append (phoneMonitor.sms.messages, msg);
326       phoneMonitor.sms.used++;
327       if (msg->Type == GST_MT && msg->Status == GSS_NOTSENTREAD)
328         unread++;
329       pthread_mutex_unlock (&smsMutex);
330     }
331     else if (error == GE_INVALIDSMSLOCATION)  /* All positions are readed */
332     {
333       g_free (msg);
334       break;
335     }
336     else
337       g_free (msg);
338
339     /* FIXME: Why is any delay here?
340      */
341     /* usleep (750000); */
342   }
343   /* Update it after the whole run as otherwise "Refreshing SMSes..."
344    * would collide with "Short Message received" message.
345    */
346   phoneMonitor.sms.unRead = unread;
347 }
348
349
350 static gint A_GetMemoryStatus (gpointer data)
351 {
352   GSM_Error error;
353   D_MemoryStatus *ms = (D_MemoryStatus *) data;
354   GSM_Data gdat;
355
356   error = ms->status = GE_UNKNOWN;
357
358   if (ms)
359   {
360     GSM_DataClear(&gdat);         
361     pthread_mutex_lock (&memoryMutex);
362     gdat.MemoryStatus=&(ms->memoryStatus);
363     error = ms->status = SM_Functions(GOP_GetMemoryStatus,&gdat,&xgnokii_statemachine);
364     pthread_cond_signal (&memoryCond);
365     pthread_mutex_unlock (&memoryMutex);
366   }
367
368   return (error);
369 }
370
371
372 static gint A_GetMemoryLocation (gpointer data)
373 {
374   GSM_Error error;
375   D_MemoryLocation *ml = (D_MemoryLocation *) data;
376   GSM_Data gdat;
377
378   error = ml->status = GE_UNKNOWN;
379
380   if (ml)
381   {
382     GSM_DataClear(&gdat);
383     pthread_mutex_lock (&memoryMutex);
384     gdat.PhonebookEntry=(ml->entry);
385     error = ml->status = SM_Functions(GOP_ReadPhonebook,&gdat,&xgnokii_statemachine);
386     pthread_cond_signal (&memoryCond);
387     pthread_mutex_unlock (&memoryMutex);
388   }
389
390   return (error);
391 }
392
393
394 static gint A_GetMemoryLocationAll (gpointer data)
395 {
396   GSM_PhonebookEntry entry;
397   GSM_Error error;
398   D_MemoryLocationAll *mla = (D_MemoryLocationAll *) data;
399   register gint i;
400   GSM_Data gdat;
401
402   error = mla->status = GE_NONE;
403   entry.MemoryType = mla->type;
404   GSM_DataClear(&gdat);
405   gdat.PhonebookEntry=&entry;
406
407   pthread_mutex_lock (&memoryMutex);
408   for (i = mla->min; i <= mla->max; i++)
409   {
410     entry.Location = i;
411     error = SM_Functions(GOP_ReadPhonebook,&gdat,&xgnokii_statemachine);
412     if (error != GE_NONE && error!=GE_INVALIDPHBOOKLOCATION)
413     {
414       gint err_count = 0;
415
416       while (error != GE_NONE)
417       {
418         g_print (_("%s: line %d: Can't get memory entry number %d from memory %d! %d\n"),
419                  __FILE__, __LINE__, i, entry.MemoryType, error);
420         if (err_count++ > 3)
421         {
422           mla->ReadFailed (i);
423           mla->status = error;
424           pthread_cond_signal (&memoryCond);
425           pthread_mutex_unlock (&memoryMutex);
426           return (error);
427         }
428
429         error = SM_Functions(GOP_ReadPhonebook,&gdat,&xgnokii_statemachine);
430         sleep (2);
431       }
432     }
433
434     /* If the phonebook location was invalid - just fill up the rest */
435     /* This works on a 7110 anyway...*/
436
437     if (error==GE_INVALIDPHBOOKLOCATION) {
438         entry.Empty=true;
439         entry.Name[0]=0;
440         entry.Number[0]=0;
441         for (i = mla->min; i <= mla->max; i++) {
442                 error = mla->InsertEntry (&entry);
443                 if (error != GE_NONE) break;
444         }       
445     }
446
447     error = mla->InsertEntry (&entry);
448     if (error != GE_NONE)
449       break;
450   }
451   mla->status = error;
452   pthread_cond_signal (&memoryCond);
453   pthread_mutex_unlock (&memoryMutex);
454   return (error);
455 }
456
457
458 static gint A_WriteMemoryLocation (gpointer data)
459 {
460   GSM_Error error;
461   D_MemoryLocation *ml = (D_MemoryLocation *) data;
462   GSM_Data gdat;
463
464   error = ml->status = GE_UNKNOWN;
465
466   GSM_DataClear(&gdat);
467   gdat.PhonebookEntry=(ml->entry);
468
469   if (ml)
470   {
471     pthread_mutex_lock (&memoryMutex);
472     error = ml->status = SM_Functions(GOP_WritePhonebook,&gdat,&xgnokii_statemachine);
473     pthread_cond_signal (&memoryCond);
474     pthread_mutex_unlock (&memoryMutex);
475   }
476
477   return (error);
478 }
479
480
481 static gint A_WriteMemoryLocationAll (gpointer data)
482 {
483 /*  GSM_PhonebookEntry entry; */
484   GSM_Error error;
485   D_MemoryLocationAll *mla = (D_MemoryLocationAll *) data;
486 /*  register gint i;
487 */
488   error = mla->status = GE_NONE;
489 /*  entry.MemoryType = mla->type;
490
491   pthread_mutex_lock (&memoryMutex);
492   for (i = mla->min; i <= mla->max; i++)
493   {
494     entry.Location = i;
495     error = GSM->GetMemoryLocation (&entry);
496     if (error != GE_NONE)
497     {
498       gint err_count = 0;
499
500       while (error != GE_NONE)
501       {
502         g_print (_("%s: line %d: Can't get memory entry number %d from memory %d! %d\n"),
503                  __FILE__, __LINE__, i, entry.MemoryType, error);
504         if (err_count++ > 3)
505         {
506           mla->ReadFailed (i);
507           mla->status = error;
508           pthread_cond_signal (&memoryCond);
509           pthread_mutex_unlock (&memoryMutex);
510           return (error);
511         }
512
513         error = GSM->GetMemoryLocation (&entry);
514         sleep (2);
515       }
516     }
517     error = mla->InsertEntry (&entry);
518     if (error != GE_NONE)
519       break;
520   }
521   mla->status = error;
522   pthread_cond_signal (&memoryCond);
523   pthread_mutex_unlock (&memoryMutex); */
524   return (error);
525 }
526
527
528 static gint A_GetCalendarNote (gpointer data)
529 {
530   GSM_Error error;
531   D_CalendarNote *cn = (D_CalendarNote *) data;
532
533   error = cn->status = GE_UNKNOWN;
534
535   if (cn)
536   {
537     pthread_mutex_lock (&calendarMutex);
538     error = cn->status = GSM->GetCalendarNote (cn->entry);
539     pthread_cond_signal (&calendarCond);
540     pthread_mutex_unlock (&calendarMutex);
541   }
542
543   return (error);
544 }
545
546
547 static gint A_GetCalendarNoteAll (gpointer data)
548 {
549   GSM_CalendarNote entry;
550   D_CalendarNoteAll *cna = (D_CalendarNoteAll *) data;
551   GSM_Error e;
552   register gint i = 1;
553
554   pthread_mutex_lock (&calendarMutex);
555   while (1)
556   {
557     entry.Location = i++;
558
559     if ((e = GSM->GetCalendarNote (&entry)) != GE_NONE)
560       break;
561
562     if (cna->InsertEntry (&entry) != GE_NONE)
563       break;
564   }
565
566   pthread_mutex_unlock (&calendarMutex);
567   g_free (cna);
568   if (e == GE_INVALIDCALNOTELOCATION)
569     return (GE_NONE);
570   else
571     return (e);
572 }
573
574
575 static gint A_WriteCalendarNote (gpointer data)
576 {
577   GSM_Error error;
578   D_CalendarNote *cn = (D_CalendarNote *) data;
579
580   error = cn->status = GE_UNKNOWN;
581
582   if (cn)
583   {
584     pthread_mutex_lock (&calendarMutex);
585     error = cn->status = GSM->WriteCalendarNote (cn->entry);
586     pthread_cond_signal (&calendarCond);
587     pthread_mutex_unlock (&calendarMutex);
588   }
589
590   return (error);
591 }
592
593
594 static gint A_DeleteCalendarNote (gpointer data)
595 {
596   GSM_CalendarNote *note = (GSM_CalendarNote *) data;
597   GSM_Error error = GE_UNKNOWN;
598
599   if (note)
600   {
601     error = GSM->DeleteCalendarNote (note);
602     g_free (note);
603   }
604
605   return (error);
606 }
607
608 static gint A_GetCallerGroup (gpointer data)
609 {
610   GSM_Bitmap bitmap;
611   GSM_Error error;
612   D_CallerGroup *cg = (D_CallerGroup *) data;
613   GSM_Data gdat;
614
615   error = cg->status = GE_UNKNOWN;
616
617   if (cg)
618   {
619     bitmap.type = GSM_CallerLogo;
620     bitmap.number = cg->number;
621
622     pthread_mutex_lock (&callerGroupMutex);
623     GSM_DataClear(&gdat);
624     gdat.Bitmap=&bitmap;
625     error = cg->status = SM_Functions(GOP_GetBitmap,&gdat,&xgnokii_statemachine);
626     strncpy (cg->text, bitmap.text, 256);
627     cg->text[255] = '\0';
628     pthread_cond_signal (&callerGroupCond);
629     pthread_mutex_unlock (&callerGroupMutex);
630   }
631
632   return (error);
633 }
634
635
636 static gint A_SendCallerGroup (gpointer data)
637 {
638   GSM_Bitmap bitmap;
639   D_CallerGroup *cg = (D_CallerGroup *) data;
640   GSM_Error error;
641
642   if (!cg)
643     return (GE_UNKNOWN);
644
645   bitmap.type = GSM_CallerLogo;
646   bitmap.number = cg->number;
647   if ((error = GSM->GetBitmap (&bitmap)) != GE_NONE)
648   {
649     g_free (cg);
650     return (error);
651   }
652   strncpy (bitmap.text, cg->text, 256);
653   bitmap.text[255] = '\0';
654   g_free (cg);
655   return (GSM->SetBitmap (&bitmap));
656 }
657
658
659 static gint A_GetSMSCenter (gpointer data)
660 {
661   D_SMSCenter *c = (D_SMSCenter *) data;
662   GSM_Error error;
663
664   error = c->status = GE_UNKNOWN;
665   if (c)
666   {
667     pthread_mutex_lock (&smsCenterMutex);
668     error = c->status = GSM->GetSMSCenter (c->center);
669     pthread_cond_signal (&smsCenterCond);
670     pthread_mutex_unlock (&smsCenterMutex);
671   }
672
673   return (error);
674 }
675
676
677 static gint A_SetSMSCenter (gpointer data)
678 {
679   D_SMSCenter *c = (D_SMSCenter *) data;
680   GSM_Error error;
681
682   error = c->status = GE_UNKNOWN;
683   if (c)
684   {
685     //pthread_mutex_lock (&smsCenterMutex);
686     error = c->status = GSM->SetSMSCenter (c->center);
687     g_free (c);
688     //pthread_cond_signal (&smsCenterCond);
689     //pthread_mutex_unlock (&smsCenterMutex);
690   }
691
692   return (error);
693 }
694
695
696 static gint A_SendSMSMessage (gpointer data)
697 {
698   D_SMSMessage *d = (D_SMSMessage *) data;
699   GSM_Error error;
700
701   error = d->status = GE_UNKNOWN;
702   if (d)
703   {
704     pthread_mutex_lock (&sendSMSMutex);
705     error = d->status = GSM->SendSMSMessage (d->sms);
706     pthread_cond_signal (&sendSMSCond);
707     pthread_mutex_unlock (&sendSMSMutex);
708   }
709
710   if (d->status == GE_SMSSENDOK)
711     return (GE_NONE);
712   else
713     return (error);
714 }
715
716
717 static gint A_SaveSMSMessage (gpointer data)
718 {
719   D_SMSMessage *d = (D_SMSMessage *) data;
720   GSM_Error error;
721
722   error = d->status = GE_UNKNOWN;
723   if (d)
724   {
725     pthread_mutex_lock (&saveSMSMutex);
726     error = d->status = GSM->SaveSMSMessage (d->sms);
727     pthread_cond_signal (&saveSMSCond);
728     pthread_mutex_unlock (&saveSMSMutex);
729   }
730
731   return (error);
732 }
733
734
735 static gint A_DeleteSMSMessage (gpointer data)
736 {
737   GSM_SMSMessage *sms = (GSM_SMSMessage *) data;
738   GSM_Error error = GE_UNKNOWN;
739
740   if (sms)
741   {
742     GSM_Data gdat;
743     GSM_DataClear(&gdat);
744     gdat.SMSMessage = sms;
745     error = SM_Functions(GOP_DeleteSMS, &gdat, &xgnokii_statemachine);
746     g_free (sms);
747   }
748
749   return (error);
750 }
751
752
753 static gint A_GetSpeedDial (gpointer data)
754 {
755   D_SpeedDial *d = (D_SpeedDial *) data;
756   GSM_Error error;
757
758   error = d->status = GE_UNKNOWN;
759
760   if (d)
761   {
762     pthread_mutex_lock (&speedDialMutex);
763     error = d->status = GSM->GetSpeedDial (&(d->entry));
764     pthread_cond_signal (&speedDialCond);
765     pthread_mutex_unlock (&speedDialMutex);
766   }
767
768   return (error);
769 }
770
771
772 static gint A_SendSpeedDial (gpointer data)
773 {
774   D_SpeedDial *d = (D_SpeedDial *) data;
775   GSM_Error error;
776
777   error = d->status = GE_UNKNOWN;
778
779   if (d)
780   {
781     //pthread_mutex_lock (&speedDialMutex);
782     error = d->status = GSM->SetSpeedDial (&(d->entry));
783     g_free (d);
784     //pthread_cond_signal (&speedDialCond);
785     //pthread_mutex_unlock (&speedDialMutex);
786   }
787
788   return (error);
789 }
790
791
792 static gint A_SendDTMF (gpointer data)
793 {
794   gchar *buf = (gchar *) data;
795   GSM_Error error = GE_UNKNOWN;
796
797   if (buf) 
798   {
799     error = GSM->SendDTMF (buf);
800     g_free (buf);
801   }
802
803   return (error);
804 }
805
806
807 static gint A_NetMonOnOff (gpointer data)
808 {
809   gchar screen[50];
810   gint mode = GPOINTER_TO_INT (data);
811   GSM_Error error = GE_UNKNOWN;
812
813   if (mode)
814     error = GSM->NetMonitor (0xf3, screen);
815   else
816     error = GSM->NetMonitor (0xf1, screen);
817
818   return (error);
819 }
820
821
822 static gint A_NetMonitor (gpointer data)
823 {
824   gint number = GPOINTER_TO_INT (data);
825
826   if (data == 0)
827     phoneMonitor.netmonitor.number = 0;
828   else
829     phoneMonitor.netmonitor.number = number;
830     
831   return (0);
832 }
833
834
835 static gint A_DialVoice (gpointer data)
836 {
837   gchar *number = (gchar *) data;
838   GSM_Error error = GE_UNKNOWN;
839
840   if (number)
841   {
842     error = GSM->DialVoice (number);
843     g_free (number);
844   }
845
846   return (error);
847 }
848
849
850 static gint A_GetAlarm (gpointer data)
851 {
852   D_Alarm *a = (D_Alarm *) data;
853   GSM_Error error;
854
855   error = GE_UNKNOWN;
856
857   if (a && GSM)
858   {
859     a->status = GE_UNKNOWN;
860     pthread_mutex_lock (&alarmMutex);
861     error = a->status = GSM->GetAlarm (0, &(a->time));
862     pthread_cond_signal (&alarmCond);
863     pthread_mutex_unlock (&alarmMutex);
864   }
865
866   return (error);
867 }
868
869
870 static gint A_SetAlarm (gpointer data)
871 {
872   D_Alarm *a = (D_Alarm *) data;
873   GSM_Error error;
874
875   error = a->status = GE_UNKNOWN;
876
877   if (a)
878   {
879     error = a->status = GSM->SetAlarm (0, &(a->time));
880     g_free (a);
881   }
882
883   return (error);
884 }
885
886
887 static gint A_SendKeyStroke (gpointer data)
888 {
889   gchar *buf = (gchar *) data;
890
891   if (buf) 
892   {
893 #if 0
894     FB61_TX_SendMessage(0x07, 0x0c, buf);
895 #endif
896     g_free (buf);
897   }
898
899   return (0);
900 }
901
902 static gint A_GetBitmap(gpointer data) {
903   GSM_Error error;
904   D_Bitmap *d = (D_Bitmap *)data;
905   GSM_Data gdat;
906
907   GSM_DataClear(&gdat);
908   pthread_mutex_lock(&getBitmapMutex);
909   gdat.Bitmap=d->bitmap;
910   error = d->status = SM_Functions(GOP_GetBitmap,&gdat,&xgnokii_statemachine);
911   pthread_cond_signal(&getBitmapCond);
912   pthread_mutex_unlock(&getBitmapMutex);
913   return error;
914 }
915
916 static gint A_SetBitmap(gpointer data) {
917   GSM_Error error;
918   D_Bitmap *d = (D_Bitmap *)data;
919   GSM_Bitmap bitmap;
920   GSM_Data gdat;
921   
922   GSM_DataClear(&gdat);
923   pthread_mutex_lock(&setBitmapMutex);
924   if (d->bitmap->type == GSM_CallerLogo) {
925     bitmap.type = d->bitmap->type;
926     bitmap.number = d->bitmap->number;
927     gdat.Bitmap=&bitmap;
928     error = d->status = SM_Functions(GOP_GetBitmap,&gdat,&xgnokii_statemachine);
929     if (error == GE_NONE) {
930       strncpy(d->bitmap->text,bitmap.text,sizeof(bitmap.text));
931       d->bitmap->ringtone = bitmap.ringtone;
932       gdat.Bitmap=d->bitmap;
933       error = d->status = SM_Functions(GOP_SetBitmap,&gdat,&xgnokii_statemachine);
934     }
935   } else {
936     gdat.Bitmap=d->bitmap;
937     error = d->status = SM_Functions(GOP_SetBitmap,&gdat,&xgnokii_statemachine);
938   }
939   pthread_cond_signal(&setBitmapCond);
940   pthread_mutex_unlock(&setBitmapMutex);
941   return error;
942 }
943
944 static gint A_GetNetworkInfo(gpointer data) {
945   GSM_Error error;
946   D_NetworkInfo *d = (D_NetworkInfo *)data;
947   GSM_Data gdat;
948   
949   GSM_DataClear(&gdat);
950
951   pthread_mutex_lock(&getNetworkInfoMutex);
952   gdat.NetworkInfo=d->info;
953   error = d->status = SM_Functions(GOP_GetNetworkInfo,&gdat,&xgnokii_statemachine);
954   pthread_cond_signal(&getNetworkInfoCond);
955   pthread_mutex_unlock(&getNetworkInfoMutex);
956   return error;
957 }
958
959 static gint A_Exit (gpointer data)
960 {
961   pthread_exit (0);
962   return (0); /* just to be proper */
963 }
964
965
966 gint (*DoAction[])(gpointer) = {
967   A_GetMemoryStatus,
968   A_GetMemoryLocation,
969   A_GetMemoryLocationAll,
970   A_WriteMemoryLocation,
971   A_WriteMemoryLocationAll,
972   A_GetCalendarNote,
973   A_GetCalendarNoteAll,
974   A_WriteCalendarNote,
975   A_DeleteCalendarNote,
976   A_GetCallerGroup,
977   A_SendCallerGroup,
978   A_GetSMSCenter,
979   A_SetSMSCenter,
980   A_SendSMSMessage,
981   A_SaveSMSMessage,
982   A_DeleteSMSMessage,
983   A_GetSpeedDial,
984   A_SendSpeedDial,
985   A_SendDTMF,
986   A_NetMonOnOff,
987   A_NetMonitor,
988   A_DialVoice,
989   A_GetAlarm,
990   A_SetAlarm,
991   A_SendKeyStroke,
992   A_GetBitmap,
993   A_SetBitmap,
994   A_GetNetworkInfo,
995   A_Exit
996 };
997
998
999 void *GUI_Connect (void *a)
1000 {
1001   /* Define required unit types for RF and Battery level meters. */
1002   GSM_RFUnits rf_units = GRF_Percentage;
1003   GSM_BatteryUnits batt_units = GBU_Percentage;
1004
1005   GSM_DateTime Alarm;
1006   GSM_SMSStatus SMSStatus = {0, 0, 0};
1007   gchar number[INCALL_NUMBER_LENGTH];
1008   PhoneEvent *event;
1009   GSM_Error error;
1010   gint status;
1011   GSM_Data data;
1012
1013   GSM_DataClear(&data);
1014
1015 # ifdef XDEBUG
1016   g_print ("Initializing connection...\n");
1017 # endif
1018
1019   phoneMonitor.working = _("Connecting...");
1020   while (fbusinit (true))
1021     sleep (1);
1022
1023 # ifdef XDEBUG
1024   g_print ("Phone connected. Starting monitoring...\n");
1025 # endif
1026
1027   sleep(1);
1028
1029   data.RFLevel=&phoneMonitor.rfLevel;
1030   data.RFUnits=&rf_units;
1031   data.PowerSource=&phoneMonitor.powerSource;
1032   data.BatteryUnits=&batt_units; 
1033   data.BatteryLevel=&phoneMonitor.batteryLevel;
1034   data.DateTime=&Alarm;
1035   data.SMSStatus=&SMSStatus;
1036   data.IncomingCallNr=number;
1037
1038   while (1)
1039   {
1040     phoneMonitor.working = NULL;
1041
1042     /* FIXME - this loop goes mad on my 7110 - so I've put in a usleep */
1043     usleep(50000);
1044
1045     if (SM_Functions(GOP_GetRFLevel,&data,&xgnokii_statemachine) != GE_NONE)
1046       phoneMonitor.rfLevel = -1;
1047
1048     if (rf_units == GRF_Arbitrary)
1049       phoneMonitor.rfLevel *= 25;
1050
1051     if (SM_Functions(GOP_GetPowersource,&data,&xgnokii_statemachine)  == GE_NONE 
1052         && phoneMonitor.powerSource == GPS_ACDC)
1053     {
1054       if (phoneMonitor.batteryLevel < 0 || phoneMonitor.batteryLevel > 100)
1055         phoneMonitor.batteryLevel = 100;
1056     }
1057     else {
1058       if (SM_Functions(GOP_GetBatteryLevel,&data,&xgnokii_statemachine) != GE_NONE)
1059         phoneMonitor.batteryLevel = -1;
1060       if (batt_units == GBU_Arbitrary)
1061         phoneMonitor.batteryLevel *= 25;
1062     }
1063
1064     if (SM_Functions(GOP_GetAlarm,&data,&xgnokii_statemachine) == GE_NONE && Alarm.AlarmEnabled != 0)
1065       phoneMonitor.alarm = TRUE;
1066     else
1067       phoneMonitor.alarm = FALSE;
1068
1069     if (SM_Functions(GOP_GetSMSStatus,&data,&xgnokii_statemachine) == GE_NONE)
1070     {
1071       /* Change of "UnRead" shouldn't be interesting - user may have read some of his
1072        * SMSes by the phone interface.
1073        */
1074       if (phoneMonitor.sms.unRead != SMSStatus.UnRead ||
1075           phoneMonitor.sms.used   != SMSStatus.Used ||
1076           phoneMonitor.sms.slots  != SMSStatus.Slots)   /* shouldn't change, just to be sure */
1077       {
1078         /* We are primarily interested in SMSStatus.Slots so try to fix it up if it is broken
1079          */
1080         if (SMSStatus.UnRead > SMSStatus.Used)
1081           SMSStatus.Used = SMSStatus.UnRead;
1082         if (SMSStatus.Used > SMSStatus.Slots)
1083           SMSStatus.Slots = SMSStatus.Used;
1084         phoneMonitor.sms.slots = SMSStatus.Slots;       /* shouldn't change, just to be sure */
1085         /* phoneMonitor.sms.{unRead,used} will be updated by RefreshSMS()
1086          */
1087
1088         phoneMonitor.working = _("Refreshing SMSes...");
1089         RefreshSMS (SMSStatus.Slots);
1090         phoneMonitor.working = NULL;
1091       }
1092
1093     }
1094
1095     if (SM_Functions(GOP_GetIncomingCallNr,&data,&xgnokii_statemachine) == GE_NONE)
1096     {
1097 #   ifdef XDEBUG
1098       g_print ("Call in progress: %s\n", phoneMonitor.call.callNum);
1099 #   endif
1100
1101       GSM->GetDisplayStatus (&status);
1102       if (status & (1<<DS_Call_In_Progress))
1103       {
1104         pthread_mutex_lock (&callMutex);
1105         phoneMonitor.call.callInProgress = CS_InProgress;
1106         pthread_mutex_unlock (&callMutex);
1107       }
1108       else
1109       {
1110         pthread_mutex_lock (&callMutex);
1111         phoneMonitor.call.callInProgress = CS_Waiting;
1112         strncpy (phoneMonitor.call.callNum, number, INCALL_NUMBER_LENGTH);
1113         pthread_mutex_unlock (&callMutex);
1114       }
1115     }
1116     else
1117     {
1118       pthread_mutex_lock (&callMutex);
1119       phoneMonitor.call.callInProgress = CS_Idle;
1120       *phoneMonitor.call.callNum = '\0';
1121       pthread_mutex_unlock (&callMutex);
1122     }
1123
1124     pthread_mutex_lock (&netMonMutex);
1125     if (phoneMonitor.netmonitor.number)
1126     {
1127       GSM->NetMonitor (phoneMonitor.netmonitor.number,
1128                        phoneMonitor.netmonitor.screen);
1129       GSM->NetMonitor (3, phoneMonitor.netmonitor.screen3);
1130       GSM->NetMonitor (4, phoneMonitor.netmonitor.screen4);
1131       GSM->NetMonitor (5, phoneMonitor.netmonitor.screen5);
1132     }
1133     else
1134     {
1135       *phoneMonitor.netmonitor.screen = *phoneMonitor.netmonitor.screen3 = 
1136       *phoneMonitor.netmonitor.screen4 = *phoneMonitor.netmonitor.screen5 = '\0';
1137     }
1138     pthread_mutex_unlock (&netMonMutex);
1139
1140     while ((event = RemoveEvent ()) != NULL)
1141     {
1142 #     ifdef XDEBUG      
1143       g_print ("Processing Event: %d\n", event->event);
1144 #     endif
1145       phoneMonitor.working = _("Working...");
1146       if (event->event <= Event_Exit)
1147         if ((error = DoAction[event->event] (event->data)) != GE_NONE)
1148           g_print (_("Event %d failed with return code %d!\n"), event->event, error);
1149       g_free (event);
1150     }
1151   }
1152 }