1 /*
2 
3   S M S D
4 
5   A Linux/Unix tool for the mobile phones.
6 
7   This file is part of gnokii.
8 
9   Gnokii is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13 
14   Gnokii is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with gnokii; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 
23   Copyright (C) 2002-2011 Jan Derfinak
24 
25   This file is a module to smsd for file access.
26 
27 */
28 
29 #include "config.h"
30 
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <dirent.h>
35 #include <string.h>
36 #include <glib.h>
37 #include "smsd.h"
38 #include "gnokii.h"
39 #include "compat.h"
40 #include "utils.h"
41 
42 static gchar *action;
43 static gchar *spool;
44 
DB_Bye(void)45 GNOKII_API void DB_Bye (void)
46 {
47   return;
48 }
49 
50 
DB_ConnectInbox(DBConfig connect)51 GNOKII_API gint DB_ConnectInbox (DBConfig connect)
52 {
53   struct stat status;
54 
55   if (connect.user[0] != '\0')
56   {
57     if ((stat (connect.user, &status)) != 0)
58     {
59       g_print (_("Cannot stat file %s!\n"), connect.user);
60       return (1);
61     }
62 
63     if (!((S_IFREG & status.st_mode) &&
64         (((status.st_uid == geteuid ()) && (S_IXUSR & status.st_mode)) ||
65          ((status.st_gid == getegid ()) && (S_IXGRP & status.st_mode)) ||
66          (S_IXGRP & status.st_mode))))
67     {
68       g_print (_("File %s is not regular file or\nyou have not executable permission to this file!\n"),
69                connect.user);
70       return (2);
71     }
72   }
73 
74   action = connect.user;
75 
76   return (0);
77 }
78 
79 
DB_ConnectOutbox(DBConfig connect)80 GNOKII_API gint DB_ConnectOutbox (DBConfig connect)
81 {
82   struct stat status;
83 
84   if (connect.host[0] == '\0')
85     g_print (_("You have not set spool directory, sms sending is disabled!\n"));
86   else
87   {
88     if ((stat (connect.host, &status)) != 0)
89     {
90       g_print (_("Cannot stat file %s!\n"), connect.host);
91       return (1);
92     }
93 
94     if (!((S_IFDIR & status.st_mode) &&
95         (((status.st_uid == geteuid ()) && (S_IRUSR & status.st_mode) && (S_IWUSR & status.st_mode)) ||
96          ((status.st_gid == getegid ()) && (S_IRGRP & status.st_mode) && (S_IWGRP & status.st_mode)) ||
97          ((S_IROTH & status.st_mode) && (S_IWOTH & status.st_mode)))))
98     {
99       g_print (_("File %s is not directory or\nyou have not read and write permissions to this directory,\nsms sending is disabled!\n!"),
100                connect.host);
101       return (2);
102     }
103   }
104 
105   spool = connect.host;
106 
107   return (0);
108 }
109 
110 
DB_InsertSMS(const gn_sms * const data,const gchar * const phone)111 GNOKII_API gint DB_InsertSMS (const gn_sms * const data, const gchar * const phone)
112 {
113   FILE *p;
114   GString *buf;
115   gchar *text;
116 
117   text = strEscape ((gchar *) data->user_data[0].u.text);
118 
119   if (action[0] == '\0')
120     g_print ("Number: %s, Date: %02d-%02d-%02d %02d:%02d:%02d\nText:\n%s\n", \
121              data->remote.number, data->smsc_time.year, data->smsc_time.month, \
122              data->smsc_time.day, data->smsc_time.hour, data->smsc_time.minute, \
123              data->smsc_time.second, text);
124   else
125   {
126     buf = g_string_sized_new (256);
127     g_string_printf (buf, "%s %s \"%02d-%02d-%02d %02d:%02d:%02d\"", \
128                      action, data->remote.number, data->smsc_time.year, \
129                      data->smsc_time.month, data->smsc_time.day, \
130                      data->smsc_time.hour, data->smsc_time.minute, \
131                      data->smsc_time.second);
132     if ((p = popen (buf->str, "w")) == NULL)
133     {
134       g_free (text);
135       g_string_free (buf, TRUE);
136       return (1);
137     }
138 
139     g_string_free (buf, TRUE);
140 
141     fprintf (p, "%s", text);
142     pclose (p);
143   }
144 
145   g_free (text);
146 
147   return (0);
148 }
149 
150 
DB_Look(const gchar * const phone)151 GNOKII_API gint DB_Look (const gchar * const phone)
152 {
153   DIR *dir;
154   struct dirent *dirent;
155   FILE *smsFile;
156   GString *buf;
157   gint numError, error;
158   gint empty = 1;
159 
160 
161   if (spool[0] == '\0')  // if user don't set spool dir, sending is disabled
162     return (SMSD_NOK);
163 
164   if ((dir = opendir (spool)) == NULL)
165   {
166     g_print (_("Cannot open directory %s\n"), spool);
167     return (SMSD_NOK);
168   }
169 
170   buf = g_string_sized_new (64);
171 
172   while ((dirent = readdir (dir)))
173   {
174     gn_sms sms;
175     gint slen = 0;
176 
177     if (strcmp (dirent->d_name, ".") == 0 || strcmp (dirent->d_name, "..") == 0 ||
178         strncmp (dirent->d_name, "ERR.", 4) == 0)
179       continue;
180 
181     g_string_printf (buf, "%s/%s", spool, dirent->d_name);
182 
183     if ((smsFile = fopen (buf->str, "r")) == NULL)
184     {
185       g_print (_("Can't open file %s for reading!\n"), buf->str);
186       continue;
187     }
188 
189     empty = 0;
190     gn_sms_default_submit (&sms);
191     memset (&sms.remote.number, 0, sizeof (sms.remote.number));
192 
193     if (fgets (sms.remote.number, sizeof (sms.remote.number), smsFile))
194       slen = strlen (sms.remote.number);
195     if (slen < 1)
196     {
197       error = -1;
198       fclose (smsFile);
199       g_print (_("Remote number is empty in %s!\n"), buf->str);
200       goto handle_file;
201     }
202 
203     if (sms.remote.number[slen - 1] == '\n')
204       sms.remote.number[slen - 1] = '\0';
205 
206     /* Initialize SMS text */
207     memset (&sms.user_data[0].u.text, 0, sizeof (sms.user_data[0].u.text));
208 
209     slen = fread ((gchar *) sms.user_data[0].u.text, 1, GN_SMS_MAX_LENGTH, smsFile);
210     if (slen > 0 && sms.user_data[0].u.text[slen - 1] == '\n')
211       sms.user_data[0].u.text[slen - 1] = '\0';
212 
213     fclose (smsFile);
214 
215 //    sms.delivery_report = (smsdConfig.smsSets & SMSD_READ_REPORTS);
216 
217     if (sms.remote.number[0] == '+')
218       sms.remote.type = GN_GSM_NUMBER_International;
219     else
220       sms.remote.type = GN_GSM_NUMBER_Unknown;
221 
222     sms.user_data[0].length = strlen ((gchar *) sms.user_data[0].u.text);
223     sms.user_data[0].type = GN_SMS_DATA_Text;
224     sms.user_data[1].type = GN_SMS_DATA_None;
225     if (!gn_char_def_alphabet (sms.user_data[0].u.text))
226        sms.dcs.u.general.alphabet = GN_SMS_DCS_UCS2;
227 
228 
229     gn_log_xdebug ("Sending SMS: %s, %s\n", sms.remote.number, sms.user_data[0].u.text);
230 
231     numError = 0;
232     do
233     {
234       error = WriteSMS (&sms);
235       sleep (1);
236     }
237     while ((error == GN_ERR_TIMEOUT || error == GN_ERR_FAILED) && numError++ < 3);
238 
239  handle_file:
240     if (error == GN_ERR_NONE)
241     {
242       if (unlink (buf->str))
243         g_print (_("Cannot unlink %s."), buf->str);
244     }
245     else
246     {
247       GString *buf2;
248 
249       buf2 = g_string_sized_new (64);
250       g_string_printf (buf2, "%s/ERR.%s", spool, dirent->d_name);
251 
252       g_print (_("Cannot send sms from file %s\n"), buf->str);
253       if (rename (buf->str, buf2->str))
254       {
255         g_print (_("Cannot rename file %s to %s. Trying to unlink it.\n"),
256                  buf->str, buf2->str);
257         if (unlink (buf->str))
258           g_print (_("Cannot unlink %s."), buf->str);
259       }
260       g_string_free (buf2, TRUE);
261     }
262   }
263 
264   g_string_free (buf, TRUE);
265   closedir (dir);
266 
267   if (empty)
268     return (SMSD_OUTBOXEMPTY);
269   else
270     return (SMSD_OK);
271 }
272