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