00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00063 #include "gw-config.h"
00064
00065 #include <unistd.h>
00066 #include <sys/types.h>
00067 #include <sys/stat.h>
00068 #include <fcntl.h>
00069 #include <dirent.h>
00070 #include <errno.h>
00071
00072 #include "gwlib/gwlib.h"
00073 #include "msg.h"
00074 #include "sms.h"
00075 #include "bearerbox.h"
00076 #include "bb_store.h"
00077
00078
00079
00080 #define MAX_DIRS 100
00081
00082 static Octstr *spool;
00083 static Counter *counter;
00084 static List *loaded;
00085
00086
00087 static int store_spool_dump()
00088 {
00089
00090 return 0;
00091 }
00092
00093
00094 static long store_spool_messages()
00095 {
00096 return counter ? counter_value(counter) : -1;
00097 }
00098
00099
00100 static int for_each_file(const Octstr *dir_s, int ignore_err, void(*cb)(const Octstr*, void*), void *data)
00101 {
00102 DIR *dir;
00103 struct dirent *ent;
00104 struct stat stat;
00105 int ret = 0;
00106
00107 if ((dir = opendir(octstr_get_cstr(dir_s))) == NULL) {
00108 error(errno, "Could not open directory `%s'", octstr_get_cstr(dir_s));
00109 return -1;
00110 }
00111 while((ent = readdir(dir)) != NULL) {
00112 Octstr *filename;
00113 if (*(ent->d_name) == '.')
00114 continue;
00115 filename = octstr_format("%S/%s", dir_s, ent->d_name);
00116 if (lstat(octstr_get_cstr(filename), &stat) == -1) {
00117 if (!ignore_err)
00118 error(errno, "Could not get stat for `%s'", octstr_get_cstr(filename));
00119 ret = -1;
00120 } else if (S_ISDIR(stat.st_mode) && for_each_file(filename, ignore_err, cb, data) == -1) {
00121 ret = -1;
00122 } else if (S_ISREG(stat.st_mode) && cb != NULL)
00123 cb(filename, data);
00124 octstr_destroy(filename);
00125 if (ret == -1 && ignore_err)
00126 ret = 0;
00127 else if (ret == -1)
00128 break;
00129 }
00130 closedir(dir);
00131
00132 return ret;
00133 }
00134
00135
00136 struct status {
00137 const char *format;
00138 Octstr *status;
00139 };
00140
00141
00142 static void status_cb(const Octstr *filename, void *d)
00143 {
00144 struct status *data = d;
00145 struct tm tm;
00146 char id[UUID_STR_LEN + 1];
00147 Octstr *msg_s;
00148 Msg *msg;
00149
00150 msg_s = octstr_read_file(octstr_get_cstr(filename));
00151 msg = store_msg_unpack(msg_s);
00152 octstr_destroy(msg_s);
00153 if (msg == NULL)
00154 return;
00155
00156
00157 #if LOG_TIMESTAMP_LOCALTIME
00158 tm = gw_localtime(msg->sms.time);
00159 #else
00160 tm = gw_gmtime(msg->sms.time);
00161 #endif
00162 if (msg->sms.udhdata)
00163 octstr_binary_to_hex(msg->sms.udhdata, 1);
00164 if (msg->sms.msgdata &&
00165 (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2 ||
00166 (msg->sms.coding == DC_UNDEF && msg->sms.udhdata)))
00167 octstr_binary_to_hex(msg->sms.msgdata, 1);
00168
00169 uuid_unparse(msg->sms.id, id);
00170
00171 octstr_format_append(data->status, data->format,
00172 id,
00173 (msg->sms.sms_type == mo ? "MO" :
00174 msg->sms.sms_type == mt_push ? "MT-PUSH" :
00175 msg->sms.sms_type == mt_reply ? "MT-REPLY" :
00176 msg->sms.sms_type == report_mo ? "DLR-MO" :
00177 msg->sms.sms_type == report_mt ? "DLR-MT" : ""),
00178 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
00179 tm.tm_hour, tm.tm_min, tm.tm_sec,
00180 (msg->sms.sender ? octstr_get_cstr(msg->sms.sender) : ""),
00181 (msg->sms.receiver ? octstr_get_cstr(msg->sms.receiver) : ""),
00182 (msg->sms.smsc_id ? octstr_get_cstr(msg->sms.smsc_id) : ""),
00183 (msg->sms.boxc_id ? octstr_get_cstr(msg->sms.boxc_id) : ""),
00184 (msg->sms.udhdata ? octstr_get_cstr(msg->sms.udhdata) : ""),
00185 (msg->sms.msgdata ? octstr_get_cstr(msg->sms.msgdata) : ""));
00186
00187 msg_destroy(msg);
00188 }
00189
00190
00191 static Octstr *store_spool_status(int status_type)
00192 {
00193 Octstr *ret = octstr_create("");
00194 const char *format;
00195 struct status data;
00196
00197
00198 if (spool == NULL)
00199 return ret;
00200
00201
00202 if (status_type == BBSTATUS_HTML) {
00203 octstr_append_cstr(ret, "<table border=1>\n"
00204 "<tr><td>SMS ID</td><td>Type</td><td>Time</td><td>Sender</td><td>Receiver</td>"
00205 "<td>SMSC ID</td><td>BOX ID</td><td>UDH</td><td>Message</td>"
00206 "</tr>\n");
00207
00208 format = "<tr><td>%s</td><td>%s</td>"
00209 "<td>%04d-%02d-%02d %02d:%02d:%02d</td>"
00210 "<td>%s</td><td>%s</td><td>%s</td>"
00211 "<td>%s</td><td>%s</td><td>%s</td></tr>\n";
00212 } else if (status_type == BBSTATUS_XML) {
00213 format = "<message>\n\t<id>%s</id>\n\t<type>%s</type>\n\t"
00214 "<time>%04d-%02d-%02d %02d:%02d:%02d</time>\n\t"
00215 "<sender>%s</sender>\n\t"
00216 "<receiver>%s</receiver>\n\t<smsc-id>%s</smsc-id>\n\t"
00217 "<box-id>%s</box-id>\n\t"
00218 "<udh-data>%s</udh-data>\n\t<msg-data>%s</msg-data>\n\t"
00219 "</message>\n";
00220 } else {
00221 octstr_append_cstr(ret, "[SMS ID] [Type] [Time] [Sender] [Receiver] [SMSC ID] [BOX ID] [UDH] [Message]\n");
00222 format = "[%s] [%s] [%04d-%02d-%02d %02d:%02d:%02d] [%s] [%s] [%s] [%s] [%s] [%s]\n";
00223 }
00224
00225 data.format = format;
00226 data.status = ret;
00227
00228 for_each_file(spool, 1, status_cb, &data);
00229
00230
00231 if (status_type == BBSTATUS_HTML) {
00232 octstr_append_cstr(ret,"</table>");
00233 }
00234
00235 return ret;
00236 }
00237
00238
00239 static void dispatch(const Octstr *filename, void *data)
00240 {
00241 Octstr *msg_s;
00242 Msg *msg;
00243 void(*receive_msg)(Msg*) = data;
00244
00245
00246
00247 msg_s = octstr_read_file(octstr_get_cstr(filename));
00248 if (msg_s == NULL)
00249 return;
00250 msg = store_msg_unpack(msg_s);
00251 octstr_destroy(msg_s);
00252 if (msg != NULL) {
00253 receive_msg(msg);
00254 counter_increase(counter);
00255 } else {
00256 error(0, "Could not unpack message `%s'", octstr_get_cstr(filename));
00257 }
00258 }
00259
00260
00261 static int store_spool_load(void(*receive_msg)(Msg*))
00262 {
00263 int rc;
00264
00265
00266 if (spool == NULL)
00267 return 0;
00268
00269
00270 if (receive_msg == NULL)
00271 return -1;
00272
00273 rc = for_each_file(spool, 0, dispatch, receive_msg);
00274
00275 info(0, "Loaded %ld messages from store.", counter_value(counter));
00276
00277
00278 gwlist_remove_producer(loaded);
00279
00280 return rc;
00281 }
00282
00283
00284 static int store_spool_save(Msg *msg)
00285 {
00286 char id[UUID_STR_LEN + 1];
00287 Octstr *id_s;
00288
00289
00290 if (msg_type(msg) == sms && uuid_is_null(msg->sms.id))
00291 uuid_generate(msg->sms.id);
00292
00293 if (msg_type(msg) == sms && msg->sms.time == MSG_PARAM_UNDEFINED)
00294 time(&msg->sms.time);
00295
00296 if (spool == NULL)
00297 return 0;
00298
00299
00300 gwlist_consume(loaded);
00301
00302 switch(msg_type(msg)) {
00303 case sms:
00304 {
00305 Octstr *os = store_msg_pack(msg);
00306 Octstr *filename, *dir;
00307 int fd;
00308 size_t wrc;
00309
00310 if (os == NULL) {
00311 error(0, "Could not pack message.");
00312 return -1;
00313 }
00314 uuid_unparse(msg->sms.id, id);
00315 id_s = octstr_create(id);
00316 dir = octstr_format("%S/%ld", spool, octstr_hash_key(id_s) % MAX_DIRS);
00317 octstr_destroy(id_s);
00318 if (mkdir(octstr_get_cstr(dir), S_IRUSR|S_IWUSR|S_IXUSR) == -1 && errno != EEXIST) {
00319 error(errno, "Could not create directory `%s'.", octstr_get_cstr(dir));
00320 octstr_destroy(dir);
00321 octstr_destroy(os);
00322 return -1;
00323 }
00324 filename = octstr_format("%S/%s", dir, id);
00325 octstr_destroy(dir);
00326 if ((fd = open(octstr_get_cstr(filename), O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR)) == -1) {
00327 error(errno, "Could not open file `%s'.", octstr_get_cstr(filename));
00328 octstr_destroy(filename);
00329 octstr_destroy(os);
00330 return -1;
00331 }
00332 for (wrc = 0; wrc < octstr_len(os); ) {
00333 size_t rc = write(fd, octstr_get_cstr(os) + wrc, octstr_len(os) - wrc);
00334 if (rc == -1) {
00335
00336 error(errno, "Could not write message to `%s'.", octstr_get_cstr(filename));
00337 close(fd);
00338 if (unlink(octstr_get_cstr(filename)) == -1)
00339 error(errno, "Oops, Could not remove failed file `%s'.", octstr_get_cstr(filename));
00340 octstr_destroy(os);
00341 octstr_destroy(filename);
00342 return -1;
00343 }
00344 wrc += rc;
00345 }
00346 close(fd);
00347 counter_increase(counter);
00348 octstr_destroy(filename);
00349 octstr_destroy(os);
00350 break;
00351 }
00352 case ack:
00353 {
00354 Octstr *filename;
00355 uuid_unparse(msg->ack.id, id);
00356 id_s = octstr_create(id);
00357 filename = octstr_format("%S/%ld/%s", spool, octstr_hash_key(id_s) % MAX_DIRS, id);
00358 octstr_destroy(id_s);
00359 if (unlink(octstr_get_cstr(filename)) == -1) {
00360 error(errno, "Could not unlink file `%s'.", octstr_get_cstr(filename));
00361 octstr_destroy(filename);
00362 return -1;
00363 }
00364 counter_decrease(counter);
00365 octstr_destroy(filename);
00366 break;
00367 }
00368 default:
00369 return -1;
00370 }
00371
00372 return 0;
00373 }
00374
00375
00376 static int store_spool_save_ack(Msg *msg, ack_status_t status)
00377 {
00378 int ret;
00379 Msg *nack = msg_create(ack);
00380
00381 nack->ack.nack = status;
00382 uuid_copy(nack->ack.id, msg->sms.id);
00383 nack->ack.time = msg->sms.time;
00384 ret = store_spool_save(nack);
00385 msg_destroy(nack);
00386
00387 return ret;
00388 }
00389
00390
00391 static void store_spool_shutdown()
00392 {
00393 if (spool == NULL)
00394 return;
00395
00396 counter_destroy(counter);
00397 octstr_destroy(spool);
00398 gwlist_destroy(loaded, NULL);
00399 }
00400
00401
00402 int store_spool_init(const Octstr *store_dir)
00403 {
00404 DIR *dir;
00405
00406 store_messages = store_spool_messages;
00407 store_save = store_spool_save;
00408 store_save_ack = store_spool_save_ack;
00409 store_load = store_spool_load;
00410 store_dump = store_spool_dump;
00411 store_shutdown = store_spool_shutdown;
00412 store_status = store_spool_status;
00413
00414 if (store_dir == NULL)
00415 return 0;
00416
00417
00418 if ((dir = opendir(octstr_get_cstr(store_dir))) == NULL) {
00419 error(errno, "Could not open directory `%s'", octstr_get_cstr(store_dir));
00420 return -1;
00421 }
00422 closedir(dir);
00423
00424 loaded = gwlist_create();
00425 gwlist_add_producer(loaded);
00426 spool = octstr_duplicate(store_dir);
00427 counter = counter_create();
00428
00429 return 0;
00430 }
00431
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.