ea36182fd198f4193cf15f15e1d4d26af5a825bc
[gnokii.git] / smsd / lowlevel.c
1 /*
2
3   S M S D
4
5   A Linux/Unix GUI for Nokia mobile phones.
6   Copyright (C) 1999 Pavel Janík ml., Hugh Blemings
7   & Ján Derfiòák <ja@mail.upjs.sk>.
8
9   Released under the terms of the GNU GPL, see file COPYING for more details.
10
11   $Id$
12   
13   $Log$
14   Revision 1.1.1.3  2002/04/03 00:08:22  short
15   Found in "gnokii-working" directory, some November-patches version
16
17   Revision 1.4  2001/05/30 14:36:47  pkot
18   Fix smsd to use StateMachine and let it compile.
19
20   Revision 1.3  2001/03/29 08:42:59  ja
21   Enabling compilation of smsd.
22
23   Revision 1.2  2001/02/02 08:09:57  ja
24   New dialogs for 6210/7110 in xgnokii. Fixed the smsd for new capabilty code.
25
26   
27 */
28
29 #include <unistd.h>
30 #include <pthread.h>
31 #include <string.h>
32 #include <glib.h>
33 #include "misc.h"
34 #include "gsm-common.h"
35 #include "gsm-api.h"
36 #include "fbus-6110.h"
37 #include "fbus-3810.h"
38 #include "smsd.h"
39 #include "lowlevel.h"
40
41 pthread_t monitor_th;
42 PhoneMonitor phoneMonitor;
43 pthread_mutex_t smsMutex;
44 pthread_cond_t  smsCond;
45 pthread_mutex_t sendSMSMutex;
46 pthread_cond_t  sendSMSCond;
47 static pthread_mutex_t eventsMutex;
48 static GSList *ScheduledEvents = NULL;
49
50
51 inline void InsertEvent (PhoneEvent *event)
52 {
53 # ifdef XDEBUG
54   g_print ("Inserting Event: %d\n", event->event);
55 # endif
56   pthread_mutex_lock (&eventsMutex);
57   ScheduledEvents = g_slist_prepend (ScheduledEvents, event);
58   pthread_mutex_unlock (&eventsMutex);
59 }
60
61
62 inline static PhoneEvent *RemoveEvent (void)
63 {
64   GSList *list;
65   PhoneEvent *event = NULL;
66
67   pthread_mutex_lock (&eventsMutex);
68   list = g_slist_last (ScheduledEvents);
69   if (list)
70   {
71     event = (PhoneEvent *) list->data;
72     ScheduledEvents = g_slist_remove_link (ScheduledEvents, list);
73     g_slist_free_1 (list);
74   }
75   pthread_mutex_unlock (&eventsMutex);
76
77   return (event);
78 }
79
80
81 static void InitModelInf (void)
82 {
83   gchar buf[64];
84   GSM_Error error;
85   register gint i = 0;
86
87   while ((error = GSM->GetModel(buf)) != GE_NONE && i++ < 15)
88     sleep(1);
89
90   if (error == GE_NONE)
91   {
92     g_free (phoneMonitor.phone.model);
93     phoneMonitor.phone.version = g_strdup (buf);
94     phoneMonitor.phone.model = GetModel (buf);
95     if (phoneMonitor.phone.model == NULL)
96       phoneMonitor.phone.model = g_strdup (_("unknown"));
97
98     phoneMonitor.supported = GetPhoneModel(buf)->flags;
99   }
100
101   i = 0;
102   while ((error = GSM->GetRevision (buf)) != GE_NONE && i++ < 5)
103     sleep(1);
104
105   if (error == GE_NONE)
106   {
107     g_free (phoneMonitor.phone.revision);
108     phoneMonitor.phone.revision = g_strdup (buf);
109   }
110
111   i = 0;
112   while ((error = GSM->GetIMEI (buf)) != GE_NONE && i++ < 5)
113     sleep(1);
114
115   if (error == GE_NONE)
116   {
117     g_free (phoneMonitor.phone.imei);
118     phoneMonitor.phone.imei = g_strdup (buf);
119   }
120
121
122 #ifdef XDEBUG
123   g_print ("Version: %s\n", phoneMonitor.phone.version);
124   g_print ("Model: %s\n", phoneMonitor.phone.model);
125   g_print ("IMEI: %s\n", phoneMonitor.phone.imei);
126   g_print ("Revision: %s\n", phoneMonitor.phone.revision);
127 #endif
128 }
129
130
131 static GSM_Error fbusinit(bool enable_monitoring)
132 {
133   int count=0;
134   GSM_Error error=GE_NOLINK;
135   GSM_ConnectionType connection=GCT_Serial;
136   static GSM_Statemachine sm;
137
138   if (!strcmp(smsdConfig.connection, "infrared"))
139     connection = GCT_Infrared;
140
141   /* Initialise the code for the GSM interface. */     
142
143   if (error == GE_NOLINK)
144     error = GSM_Initialise (smsdConfig.model, smsdConfig.port,
145                             smsdConfig.initlength, connection, NULL, &sm);
146
147 #ifdef XDEBUG
148   g_print ("fbusinit: error %d\n", error);
149 #endif
150
151   if (error != GE_NONE) {
152     g_print (_("GSM/FBUS init failed! (Unknown model ?). Quitting.\n"));
153     return (error);
154   }
155
156   while (count++ < 40 && *GSM_LinkOK == false)
157     usleep(50000);
158 #ifdef XDEBUG
159   g_print("After usleep. GSM_LinkOK: %d\n", *GSM_LinkOK);
160 #endif
161
162   if (*GSM_LinkOK != true) {
163     return (GE_NOLINK);
164   }
165
166   InitModelInf ();
167   return(GE_NONE);
168 }
169
170
171 void InitPhoneMonitor (void)
172 {
173   phoneMonitor.phone.model = g_strdup (_("unknown"));
174   phoneMonitor.phone.version = phoneMonitor.phone.model;
175   phoneMonitor.phone.revision = g_strdup (_("unknown"));
176   phoneMonitor.phone.imei = g_strdup (_("unknown"));
177   phoneMonitor.supported = 0;
178   phoneMonitor.working = FALSE;
179   phoneMonitor.sms.unRead = phoneMonitor.sms.used = phoneMonitor.sms.slots = 0;
180   phoneMonitor.sms.messages = NULL;
181   pthread_mutex_init (&smsMutex, NULL);
182   pthread_cond_init (&smsCond, NULL);
183   pthread_mutex_init (&sendSMSMutex, NULL);
184   pthread_cond_init (&sendSMSCond, NULL);
185   pthread_mutex_init (&eventsMutex, NULL);
186 }
187
188
189 static inline void FreeElement (gpointer data, gpointer userData)
190 {
191   g_free ((GSM_SMSMessage *) data);
192 }
193
194
195 static inline void FreeArray (GSList **array)
196 {
197   if (*array)
198   {
199     g_slist_foreach (*array, FreeElement, NULL);
200     g_slist_free (*array);
201     *array = NULL;
202   }
203 }
204
205
206 static void RefreshSMS (const gint slots)
207 {
208   GSM_Error error;
209   GSM_SMSMessage *msg;
210   register gint i;
211   gint unread = 0;
212
213 # ifdef XDEBUG
214   g_print ("RefreshSMS is running...\n");
215 # endif
216
217   pthread_mutex_lock (&smsMutex);
218   FreeArray (&(phoneMonitor.sms.messages));
219   phoneMonitor.sms.used = 0;
220 //  pthread_mutex_unlock (&smsMutex);
221
222   for (i=1; i<=slots; i++)
223   {
224     msg = g_malloc (sizeof (GSM_SMSMessage));
225     msg->MemoryType = GMT_SM;
226     msg->Location = i;
227
228     if ((error = GSM->GetSMSMessage (msg)) == GE_NONE)
229     {
230   //    pthread_mutex_lock (&smsMutex);
231       phoneMonitor.sms.messages = g_slist_append (phoneMonitor.sms.messages, msg);
232       phoneMonitor.sms.used++;
233       if (msg->Type == GST_MT && msg->Status == GSS_NOTSENTREAD)
234         unread++;
235   //    pthread_mutex_unlock (&smsMutex);
236     }
237     else if (error == GE_INVALIDSMSLOCATION)  /* All positions are readed */
238     {
239       g_free (msg);
240       break;
241     }
242     else
243       g_free (msg);
244
245     /* FIXME: Why is any delay here?
246      */
247     /* usleep (750000); */
248   }
249   /* Update it after the whole run as otherwise "Refreshing SMSes..."
250    * would collide with "Short Message received" message.
251    */
252   phoneMonitor.sms.unRead = unread;
253
254   pthread_cond_signal (&smsCond);
255   pthread_mutex_unlock (&smsMutex);
256 }
257
258
259 static gint A_SendSMSMessage (gpointer data)
260 {
261   D_SMSMessage *d = (D_SMSMessage *) data;
262   GSM_Error error;
263
264   error = d->status = GE_UNKNOWN;
265   if (d)
266   {
267     pthread_mutex_lock (&sendSMSMutex);
268     error = d->status = GSM->SendSMSMessage (d->sms);
269     pthread_cond_signal (&sendSMSCond);
270     pthread_mutex_unlock (&sendSMSMutex);
271   }
272
273   if (d->status == GE_SMSSENDOK)
274     return (GE_NONE);
275   else
276     return (error);
277 }
278
279
280 static gint A_DeleteSMSMessage (gpointer data)
281 {
282   GSM_SMSMessage *sms = (GSM_SMSMessage *) data;
283   GSM_Error error = GE_UNKNOWN;
284
285   if (sms)
286   {
287     error = GSM->DeleteSMSMessage(sms);
288 //    I don't use copy, I don't need free message.
289 //    g_free (sms);
290   }
291
292   return (error);
293 }
294
295
296 static gint A_Exit (gpointer data)
297 {
298   pthread_exit (0);
299   return (0); /* just to be proper */
300 }
301
302
303 gint (*DoAction[])(gpointer) = {
304   A_SendSMSMessage,
305   A_DeleteSMSMessage,
306   A_Exit
307 };
308
309
310 void *Connect (void *a)
311 {
312   GSM_SMSStatus SMSStatus = {0, 0, 0};
313   PhoneEvent *event;
314   GSM_Error error;
315
316
317 # ifdef XDEBUG
318   g_print ("Initializing connection...\n");
319 # endif
320
321   while (fbusinit (true))
322     sleep (1);
323
324 # ifdef XDEBUG
325   g_print ("Phone connected. Starting monitoring...\n");
326 # endif
327
328   while (1)
329   {
330     phoneMonitor.working = FALSE;
331
332     if (GSM->GetSMSStatus (&SMSStatus) == GE_NONE)
333     {
334       /* Change of "UnRead" shouldn't be interesting - user may have read some of his
335        * SMSes by the phone interface.
336        */
337       if (phoneMonitor.sms.unRead != SMSStatus.UnRead ||
338           phoneMonitor.sms.used   != SMSStatus.Used ||
339           phoneMonitor.sms.slots  != SMSStatus.Slots)   /* shouldn't change, just to be sure */
340       {
341         /* We are primarily interested in SMSStatus.Slots so try to fix it up if it is broken
342          */
343         if (SMSStatus.UnRead > SMSStatus.Used)
344           SMSStatus.Used = SMSStatus.UnRead;
345         if (SMSStatus.Used > SMSStatus.Slots)
346           SMSStatus.Slots = SMSStatus.Used;
347         phoneMonitor.sms.slots = SMSStatus.Slots;       /* shouldn't change, just to be sure */
348         /* phoneMonitor.sms.{unRead,used} will be updated by RefreshSMS()
349          */
350
351         phoneMonitor.working = TRUE;
352         RefreshSMS (SMSStatus.Slots);
353         phoneMonitor.working = FALSE;
354       }
355
356       phoneMonitor.sms.unRead = SMSStatus.UnRead;
357     }
358
359     while ((event = RemoveEvent ()) != NULL)
360     {
361 #     ifdef XDEBUG      
362       g_print ("Processing Event: %d\n", event->event);
363 #     endif
364       phoneMonitor.working = TRUE;
365       if (event->event <= Event_Exit)
366         if (((error = DoAction[event->event] (event->data)) != GE_NONE) && error != GE_SMSSENDOK)
367           g_print (_("Event %d failed with return code %d!\n"), event->event, error);
368       g_free (event);
369     }
370   }
371 }