Found in "gnokii-working" directory, some November-patches version
[gnokii.git] / smsd / db.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   Last modification: Sun Dec 17 2000
12   Modified by Jan Derfinak
13
14 */
15
16 #define ATS_PRAHA 1
17
18 #include <string.h>
19 #include <glib.h>
20 #include <pgsql/libpq-fe.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <errno.h>
26
27 #include "db.h"
28 #include "smsd.h"
29 #include "gsm-common.h"
30 #include "gsm-ringtones.h"
31 #include "gsm-filetypes.h"
32
33 static PGconn *connIn = NULL;
34 static PGconn *connOut = NULL;
35
36 void DB_Bye (void)
37 {
38   if (connIn)
39     PQfinish (connIn);
40   
41   if (connOut)
42     PQfinish (connOut);
43 }
44
45
46 gint DB_ConnectInbox (const gchar * const conninfo)
47 {
48   connIn = PQconnectdb (conninfo);
49   
50   if (PQstatus (connIn) == CONNECTION_BAD)
51   {
52      g_print ("Connection to database '%s' failed.\n", conninfo);
53      g_print ("%s", PQerrorMessage(connIn));
54      return (1);
55   }
56
57   return (0);
58 }
59
60
61 gint DB_ConnectOutbox (const gchar * const conninfo)
62 {
63   connOut = PQconnectdb (conninfo);
64   
65   if (PQstatus (connOut) == CONNECTION_BAD)
66   {
67      g_print ("Connection to database '%s' failed.\n", conninfo);
68      g_print ("%s", PQerrorMessage(connOut));
69      return (1);
70   }
71
72   return (0);
73 }
74
75
76 gint DB_InsertSMS (const GSM_SMSMessage * const data)
77 {
78   GString *buf;
79   PGresult *res;
80     
81   buf = g_string_sized_new (128);
82   g_string_sprintf (buf, "INSERT INTO inbox VALUES ('%s',
83                     '%02d-%02d-%02d %02d:%02d:%02d+01', 'now', '%s', 'f')",
84                     data->Sender, data->Time.Year + 2000, data->Time.Month,
85                     data->Time.Day, data->Time.Hour, data->Time.Minute,
86                     data->Time.Second, data->MessageText);
87   res = PQexec(connIn, buf->str);
88   g_string_free(buf, TRUE);
89   if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
90   {
91     PQclear (res);
92     return (1);
93   }
94   
95   PQclear (res);
96     
97   return (0);
98 }
99
100 #define DBL_FieldString "id, number, text, hexencode, type, fromfile, netcode, udhpresent, longuseudh, eightbit, smsc"
101 enum DBL_Field {
102   DBLF_id,
103   DBLF_number,
104   DBLF_text,
105   DBLF_hexencode,
106   DBLF_type,
107   DBLF_fromfile,
108   DBLF_netcode,
109   DBLF_udhpresent,
110   DBLF_longuseudh,
111   DBLF_eightbit,
112   DBLF_smsc,
113   };
114
115 #define DBL_true  "t"
116 #define DBL_false "f"
117
118 static int DBL_safestrcasecmp(const char *s1,const char *s2)
119 {
120         if (!s1 || !s2)
121                 return((!!s1)-(!!s2));
122         return(strcasecmp(s1,s2));
123 }
124
125 void DB_Look (void)
126 {
127   GString *buf;
128   PGresult *res1, *res2;
129   register int i;
130
131   buf = g_string_sized_new (128);
132
133 #ifndef ATS_PRAHA
134   g_string_sprintf (buf, "BEGIN");
135   res1 = PQexec(connOut, buf->str);
136   PQclear (res1);
137 #endif
138
139   g_string_sprintf (buf, "SELECT " DBL_FieldString " FROM outbox \
140                           WHERE processed='f' FOR UPDATE");
141
142   res1 = PQexec(connOut, buf->str);
143   if (!res1 || PQresultStatus (res1) != PGRES_TUPLES_OK)
144   {
145     g_print ("%s\n", PQcmdStatus (res1));
146     PQclear (res1);
147     g_print ("%d: SELECT FROM command failed\n", __LINE__);
148     res1 = PQexec (connOut, "ROLLBACK TRANSACTION");
149     PQclear (res1);
150     g_string_free (buf, TRUE);
151     return;
152   }
153
154   for (i = 0; i < PQntuples (res1); i++)
155   {
156     GSM_SMSMessage sms;
157     char *type = PQgetvalue (res1, i, DBLF_type);
158     bool fromfile = !DBL_safestrcasecmp(DBL_true, PQgetvalue (res1, i, DBLF_fromfile));
159     char *smsc = PQgetvalue (res1, i, DBLF_smsc);
160     char *smsbuf = PQgetvalue (res1, i, DBLF_text);
161     size_t smsbuflen = strlen(smsbuf);
162     bool sendlogo;
163     
164     if (!smsc)
165       sms.MessageCenter.No = 1;
166     else {
167       sms.MessageCenter.No = 0;
168       if (strlen(smsc)+1 > sizeof(sms.MessageCenter.Number))
169         continue;       /* error */
170       strcpy(sms.MessageCenter.Number, smsc);
171       }
172
173     sms.Type = GST_MO;
174     sms.Class = -1;
175     sms.Compression = false;
176     sms.EightBit = !DBL_safestrcasecmp(DBL_true, PQgetvalue (res1, i, DBLF_eightbit));
177     sms.Validity = 4320;
178     sms.UDHPresent = !DBL_safestrcasecmp(DBL_true, PQgetvalue (res1, i, DBLF_udhpresent));
179
180     if (!DBL_safestrcasecmp(DBL_true, PQgetvalue (res1, i, DBLF_hexencode))) {
181 char *d_end = (char *)SMS_BlockFromHex(smsbuf/*d*/, smsbuf/*s*/, smsbuflen);
182
183       if (!d_end)
184         continue;
185       smsbuflen = d_end - smsbuf;
186       }
187
188     sendlogo=false;
189          if (!DBL_safestrcasecmp("ringtone"    ,type)) {
190       SMS_SetupUDH(&sms, GSM_RingtoneUDH);
191       if (fromfile) {
192 GSM_Ringtone ringtone;
193 static char ringbuf[GSM_MAX_RINGTONE_PACKAGE_LENGTH];
194 int ringbuflen=GSM_MAX_RINGTONE_PACKAGE_LENGTH;
195
196         if (GSM_ReadRingtoneFile(smsbuf, &ringtone))
197           continue;     /* error */
198         GSM_PackRingtone(&ringtone, ringbuf, &ringbuflen);
199         smsbuf=ringbuf;
200         smsbuflen=ringbuflen;
201         }
202       }
203     else if (!DBL_safestrcasecmp("oplogo"      ,type)) {
204       SMS_SetupUDH(&sms, GSM_OpLogo);
205       sendlogo=true;
206       }
207     else if (!DBL_safestrcasecmp("calleridlogo",type)) {
208       SMS_SetupUDH(&sms, GSM_CallerIDLogo);
209       sendlogo=true;
210       }
211     else { /* "text" */
212       if (fromfile) {
213 static char textbuf[GSM_MAX_CONCATENATED_SMS_LENGTH];
214 int textbuflen;
215 int fd;
216
217         if (-1==(fd=open(smsbuf,O_RDONLY)))
218           continue;     /* error */
219         if (-1==(textbuflen=read(fd,textbuf,sizeof(textbuf))))
220           continue;     /* error */
221         close(fd);
222         smsbuf=textbuf;
223         smsbuflen=textbuflen;
224         }
225       if (sms.UDHPresent) {
226 u8 len=1+(*(u8 *)smsbuf);
227
228         if (len>smsbuflen || len>sizeof(sms.UDH))
229           g_print ("%d: UDH too long: UDHlen=%d, smsbuflen=%d, sizeof(sms.UDH)=%d !!!\n", __LINE__,
230             len, smsbuflen,sizeof(sms.UDH));
231         else {
232           memcpy(sms.UDH,smsbuf,len);
233           memmove(smsbuf,smsbuf+len,smsbuflen-len);
234           smsbuflen-=len;
235           }
236         }
237       }
238
239     if (sendlogo) {
240 GSM_Bitmap bitmap;
241 static u8 bin[sizeof(bitmap.bitmap) +64/*headers safety*/];
242 u8 *d;
243 char *usernetcode=PQgetvalue (res1, i, DBLF_netcode);
244
245       if (GE_NONE!=GSM_ReadBitmapFile(smsbuf, &bitmap))
246         continue;       /* error */
247
248       d=bin;
249       if (!DBL_safestrcasecmp("oplogo"      ,type)) {
250         if (usernetcode) {
251           if (strlen(usernetcode)+1 > sizeof(bitmap.netcode))
252             continue;   /* error */
253           strcpy(bitmap.netcode, usernetcode);
254           }
255         *d++ = ((bitmap.netcode[1] & 0x0f) << 4) | (bitmap.netcode[0] & 0xf);
256         *d++ = 0xf0 | (bitmap.netcode[2] & 0x0f);
257         *d++ = ((bitmap.netcode[5] & 0x0f) << 4) | (bitmap.netcode[4] & 0xf);
258         }
259       /* Set the logo size */
260       *d++ = 0x00;         /* RFU by Nokia */
261       *d++ = bitmap.width;
262       *d++ = bitmap.height;
263       *d++ = 0x01;         /* depth=number of grayscales */
264
265       memcpy(d,bitmap.bitmap,bitmap.size);
266       d+=bitmap.size;
267
268       smsbuf=bin;
269       smsbuflen=d-bin;
270       }
271
272     strncpy (sms.Destination, PQgetvalue (res1, i, DBLF_number), GSM_MAX_DESTINATION_LENGTH + 1);
273     sms.Destination[GSM_MAX_DESTINATION_LENGTH] = '\0';
274     
275 #ifdef XDEBUG
276     g_print ("To: %s\n", sms.Destination);
277 #endif
278     
279     if (GE_SMSSENDOK == WriteSMS_deconcatenated (&sms, smsbuf, smsbuflen,
280                 !DBL_safestrcasecmp(DBL_true, PQgetvalue (res1, i, DBLF_longuseudh))))
281     {
282       g_string_sprintf (buf, "UPDATE outbox SET processed='t' WHERE id='%s'",
283                         PQgetvalue (res1, i, DBLF_id));
284       res2 = PQexec(connOut, buf->str);
285       if (!res2 || PQresultStatus (res2) != PGRES_COMMAND_OK)
286       {
287         g_print ("%s\n", PQcmdStatus (res2));
288         g_print ("%d: UPDATE command failed\n", __LINE__);
289       }
290       PQclear (res2);
291     }
292   }
293
294   PQclear (res1);
295
296 #ifndef ATS_PRAHA
297   g_string_sprintf (buf, "COMMIT");
298   res1 = PQexec(connOut, buf->str);
299   PQclear (res1);
300 #endif
301
302   g_string_free(buf, TRUE);
303
304 #ifdef ATS_PRAHA
305   if (!access("/tmp/smsd-exit",F_OK)) {
306     g_print("/tmp/smsd-exit exists, terminating\n");
307     if (unlink("/tmp/smsd-exit"))
308       g_print("/tmp/smsd-exit unlink failed: %s\n",strerror(errno));
309     exit(0);
310     }
311 #endif
312 }