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