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