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 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 146838 $")
00037
00038 #include <termios.h>
00039 #include <sys/time.h>
00040 #include <time.h>
00041 #include <ctype.h>
00042
00043 #include "asterisk/module.h"
00044 #include "asterisk/lock.h"
00045 #include "asterisk/utils.h"
00046 #include "asterisk/smdi.h"
00047 #include "asterisk/config.h"
00048 #include "asterisk/astobj.h"
00049 #include "asterisk/io.h"
00050 #include "asterisk/stringfields.h"
00051 #include "asterisk/linkedlists.h"
00052 #include "asterisk/app.h"
00053 #include "asterisk/pbx.h"
00054 #include "asterisk/channel.h"
00055
00056
00057 #define SMDI_MSG_EXPIRY_TIME 30000
00058
00059 static const char config_file[] = "smdi.conf";
00060
00061
00062 struct ast_smdi_md_queue {
00063 ASTOBJ_CONTAINER_COMPONENTS(struct ast_smdi_md_message);
00064 };
00065
00066
00067 struct ast_smdi_mwi_queue {
00068 ASTOBJ_CONTAINER_COMPONENTS(struct ast_smdi_mwi_message);
00069 };
00070
00071 struct ast_smdi_interface {
00072 ASTOBJ_COMPONENTS_FULL(struct ast_smdi_interface, SMDI_MAX_FILENAME_LEN, 1);
00073 struct ast_smdi_md_queue md_q;
00074 ast_mutex_t md_q_lock;
00075 ast_cond_t md_q_cond;
00076 struct ast_smdi_mwi_queue mwi_q;
00077 ast_mutex_t mwi_q_lock;
00078 ast_cond_t mwi_q_cond;
00079 FILE *file;
00080 int fd;
00081 pthread_t thread;
00082 struct termios mode;
00083 int msdstrip;
00084 long msg_expiry;
00085 };
00086
00087
00088 struct ast_smdi_interface_container {
00089 ASTOBJ_CONTAINER_COMPONENTS(struct ast_smdi_interface);
00090 } smdi_ifaces;
00091
00092
00093 struct mailbox_mapping {
00094
00095
00096 unsigned int cur_state:1;
00097
00098 struct ast_smdi_interface *iface;
00099 AST_DECLARE_STRING_FIELDS(
00100
00101 AST_STRING_FIELD(smdi);
00102
00103 AST_STRING_FIELD(mailbox);
00104
00105 AST_STRING_FIELD(context);
00106 );
00107 AST_LIST_ENTRY(mailbox_mapping) entry;
00108 };
00109
00110
00111 #define DEFAULT_POLLING_INTERVAL 10
00112
00113
00114 static struct {
00115
00116 pthread_t thread;
00117 ast_mutex_t lock;
00118 ast_cond_t cond;
00119
00120 AST_LIST_HEAD_NOLOCK(, mailbox_mapping) mailbox_mappings;
00121
00122 unsigned int polling_interval;
00123
00124 unsigned int stop:1;
00125
00126 struct timeval last_poll;
00127 } mwi_monitor = {
00128 .thread = AST_PTHREADT_NULL,
00129 };
00130
00131 static void ast_smdi_interface_destroy(struct ast_smdi_interface *iface)
00132 {
00133 if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) {
00134 pthread_cancel(iface->thread);
00135 pthread_join(iface->thread, NULL);
00136 }
00137
00138 iface->thread = AST_PTHREADT_STOP;
00139
00140 if (iface->file)
00141 fclose(iface->file);
00142
00143 ASTOBJ_CONTAINER_DESTROYALL(&iface->md_q, ast_smdi_md_message_destroy);
00144 ASTOBJ_CONTAINER_DESTROYALL(&iface->mwi_q, ast_smdi_mwi_message_destroy);
00145 ASTOBJ_CONTAINER_DESTROY(&iface->md_q);
00146 ASTOBJ_CONTAINER_DESTROY(&iface->mwi_q);
00147
00148 ast_mutex_destroy(&iface->md_q_lock);
00149 ast_cond_destroy(&iface->md_q_cond);
00150
00151 ast_mutex_destroy(&iface->mwi_q_lock);
00152 ast_cond_destroy(&iface->mwi_q_cond);
00153
00154 free(iface);
00155
00156 ast_module_unref(ast_module_info->self);
00157 }
00158
00159 void ast_smdi_interface_unref(struct ast_smdi_interface *iface)
00160 {
00161 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00162 }
00163
00164
00165
00166
00167
00168
00169
00170 static void ast_smdi_md_message_push(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
00171 {
00172 ast_mutex_lock(&iface->md_q_lock);
00173 ASTOBJ_CONTAINER_LINK_END(&iface->md_q, md_msg);
00174 ast_cond_broadcast(&iface->md_q_cond);
00175 ast_mutex_unlock(&iface->md_q_lock);
00176 }
00177
00178
00179
00180
00181
00182
00183
00184 static void ast_smdi_mwi_message_push(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
00185 {
00186 ast_mutex_lock(&iface->mwi_q_lock);
00187 ASTOBJ_CONTAINER_LINK_END(&iface->mwi_q, mwi_msg);
00188 ast_cond_broadcast(&iface->mwi_q_cond);
00189 ast_mutex_unlock(&iface->mwi_q_lock);
00190 }
00191
00192 static int smdi_toggle_mwi(struct ast_smdi_interface *iface, const char *mailbox, int on)
00193 {
00194 FILE *file;
00195 int i;
00196
00197 if (!(file = fopen(iface->name, "w"))) {
00198 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
00199 return 1;
00200 }
00201
00202 ASTOBJ_WRLOCK(iface);
00203
00204 fprintf(file, "%s:MWI ", on ? "OP" : "RMV");
00205
00206 for (i = 0; i < iface->msdstrip; i++)
00207 fprintf(file, "0");
00208
00209 fprintf(file, "%s!\x04", mailbox);
00210
00211 fclose(file);
00212
00213 ASTOBJ_UNLOCK(iface);
00214 ast_debug(1, "Sent MWI set message for %s on %s\n", mailbox, iface->name);
00215
00216 return 0;
00217 }
00218
00219 int ast_smdi_mwi_set(struct ast_smdi_interface *iface, const char *mailbox)
00220 {
00221 return smdi_toggle_mwi(iface, mailbox, 1);
00222 }
00223
00224 int ast_smdi_mwi_unset(struct ast_smdi_interface *iface, const char *mailbox)
00225 {
00226 return smdi_toggle_mwi(iface, mailbox, 0);
00227 }
00228
00229 void ast_smdi_md_message_putback(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
00230 {
00231 ast_mutex_lock(&iface->md_q_lock);
00232 ASTOBJ_CONTAINER_LINK_START(&iface->md_q, md_msg);
00233 ast_cond_broadcast(&iface->md_q_cond);
00234 ast_mutex_unlock(&iface->md_q_lock);
00235 }
00236
00237 void ast_smdi_mwi_message_putback(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
00238 {
00239 ast_mutex_lock(&iface->mwi_q_lock);
00240 ASTOBJ_CONTAINER_LINK_START(&iface->mwi_q, mwi_msg);
00241 ast_cond_broadcast(&iface->mwi_q_cond);
00242 ast_mutex_unlock(&iface->mwi_q_lock);
00243 }
00244
00245 enum smdi_message_type {
00246 SMDI_MWI,
00247 SMDI_MD,
00248 };
00249
00250 static inline int lock_msg_q(struct ast_smdi_interface *iface, enum smdi_message_type type)
00251 {
00252 switch (type) {
00253 case SMDI_MWI:
00254 return ast_mutex_lock(&iface->mwi_q_lock);
00255 case SMDI_MD:
00256 return ast_mutex_lock(&iface->md_q_lock);
00257 }
00258
00259 return -1;
00260 }
00261
00262 static inline int unlock_msg_q(struct ast_smdi_interface *iface, enum smdi_message_type type)
00263 {
00264 switch (type) {
00265 case SMDI_MWI:
00266 return ast_mutex_unlock(&iface->mwi_q_lock);
00267 case SMDI_MD:
00268 return ast_mutex_unlock(&iface->md_q_lock);
00269 }
00270
00271 return -1;
00272 }
00273
00274 static inline void *unlink_from_msg_q(struct ast_smdi_interface *iface, enum smdi_message_type type)
00275 {
00276 switch (type) {
00277 case SMDI_MWI:
00278 return ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q);
00279 case SMDI_MD:
00280 return ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q);
00281 }
00282 return NULL;
00283 }
00284
00285 static inline struct timeval msg_timestamp(void *msg, enum smdi_message_type type)
00286 {
00287 struct ast_smdi_md_message *md_msg = msg;
00288 struct ast_smdi_mwi_message *mwi_msg = msg;
00289
00290 switch (type) {
00291 case SMDI_MWI:
00292 return mwi_msg->timestamp;
00293 case SMDI_MD:
00294 return md_msg->timestamp;
00295 }
00296
00297 return ast_tv(0, 0);
00298 }
00299
00300 static inline void unref_msg(void *msg, enum smdi_message_type type)
00301 {
00302 struct ast_smdi_md_message *md_msg = msg;
00303 struct ast_smdi_mwi_message *mwi_msg = msg;
00304
00305 switch (type) {
00306 case SMDI_MWI:
00307 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
00308 case SMDI_MD:
00309 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
00310 }
00311 }
00312
00313 static void purge_old_messages(struct ast_smdi_interface *iface, enum smdi_message_type type)
00314 {
00315 struct timeval now = ast_tvnow();
00316 long elapsed = 0;
00317 void *msg;
00318
00319 lock_msg_q(iface, type);
00320 msg = unlink_from_msg_q(iface, type);
00321 unlock_msg_q(iface, type);
00322
00323
00324 while (msg) {
00325 elapsed = ast_tvdiff_ms(now, msg_timestamp(msg, type));
00326
00327 if (elapsed > iface->msg_expiry) {
00328
00329 unref_msg(msg, type);
00330 ast_log(LOG_NOTICE, "Purged expired message from %s SMDI %s message queue. "
00331 "Message was %ld milliseconds too old.\n",
00332 iface->name, (type == SMDI_MD) ? "MD" : "MWI",
00333 elapsed - iface->msg_expiry);
00334
00335 lock_msg_q(iface, type);
00336 msg = unlink_from_msg_q(iface, type);
00337 unlock_msg_q(iface, type);
00338 } else {
00339
00340 switch (type) {
00341 case SMDI_MD:
00342 ast_smdi_md_message_push(iface, msg);
00343 break;
00344 case SMDI_MWI:
00345 ast_smdi_mwi_message_push(iface, msg);
00346 break;
00347 }
00348 unref_msg(msg, type);
00349 break;
00350 }
00351 }
00352 }
00353
00354 static void *smdi_msg_pop(struct ast_smdi_interface *iface, enum smdi_message_type type)
00355 {
00356 void *msg;
00357
00358 purge_old_messages(iface, type);
00359
00360 lock_msg_q(iface, type);
00361 msg = unlink_from_msg_q(iface, type);
00362 unlock_msg_q(iface, type);
00363
00364 return msg;
00365 }
00366
00367 enum {
00368 OPT_SEARCH_TERMINAL = (1 << 0),
00369 OPT_SEARCH_NUMBER = (1 << 1),
00370 };
00371
00372 static void *smdi_msg_find(struct ast_smdi_interface *iface,
00373 enum smdi_message_type type, const char *search_key, struct ast_flags options)
00374 {
00375 void *msg = NULL;
00376
00377 purge_old_messages(iface, type);
00378
00379 switch (type) {
00380 case SMDI_MD:
00381 if (ast_test_flag(&options, OPT_SEARCH_TERMINAL)) {
00382 struct ast_smdi_md_message *md_msg = NULL;
00383
00384
00385
00386 ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
00387 if (!strcasecmp(iterator->mesg_desk_term, search_key))
00388 md_msg = ASTOBJ_REF(iterator);
00389 } while (0); );
00390
00391 msg = md_msg;
00392 } else if (ast_test_flag(&options, OPT_SEARCH_NUMBER)) {
00393 struct ast_smdi_md_message *md_msg = NULL;
00394
00395
00396
00397 ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
00398 if (!strcasecmp(iterator->mesg_desk_num, search_key))
00399 md_msg = ASTOBJ_REF(iterator);
00400 } while (0); );
00401
00402 msg = md_msg;
00403 } else {
00404
00405 msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, search_key);
00406 }
00407 break;
00408 case SMDI_MWI:
00409 msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, search_key);
00410 break;
00411 }
00412
00413 return msg;
00414 }
00415
00416 static void *smdi_message_wait(struct ast_smdi_interface *iface, int timeout,
00417 enum smdi_message_type type, const char *search_key, struct ast_flags options)
00418 {
00419 struct timeval start;
00420 long diff = 0;
00421 void *msg;
00422 ast_cond_t *cond = NULL;
00423 ast_mutex_t *lock = NULL;
00424
00425 switch (type) {
00426 case SMDI_MWI:
00427 cond = &iface->mwi_q_cond;
00428 lock = &iface->mwi_q_lock;
00429 break;
00430 case SMDI_MD:
00431 cond = &iface->md_q_cond;
00432 lock = &iface->md_q_lock;
00433 break;
00434 }
00435
00436 start = ast_tvnow();
00437
00438 while (diff < timeout) {
00439 struct timespec ts = { 0, };
00440 struct timeval wait;
00441
00442 lock_msg_q(iface, type);
00443
00444 if ((msg = smdi_msg_find(iface, type, search_key, options))) {
00445 unlock_msg_q(iface, type);
00446 return msg;
00447 }
00448
00449 wait = ast_tvadd(start, ast_tv(0, timeout));
00450 ts.tv_sec = wait.tv_sec;
00451 ts.tv_nsec = wait.tv_usec * 1000;
00452
00453
00454
00455
00456 ast_cond_timedwait(cond, lock, &ts);
00457
00458 if ((msg = smdi_msg_find(iface, type, search_key, options))) {
00459 unlock_msg_q(iface, type);
00460 return msg;
00461 }
00462
00463 unlock_msg_q(iface, type);
00464
00465
00466 diff = ast_tvdiff_ms(ast_tvnow(), start);
00467 }
00468
00469 return NULL;
00470 }
00471
00472 struct ast_smdi_md_message *ast_smdi_md_message_pop(struct ast_smdi_interface *iface)
00473 {
00474 return smdi_msg_pop(iface, SMDI_MD);
00475 }
00476
00477 struct ast_smdi_md_message *ast_smdi_md_message_wait(struct ast_smdi_interface *iface, int timeout)
00478 {
00479 struct ast_flags options = { 0 };
00480 return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options);
00481 }
00482
00483 struct ast_smdi_mwi_message *ast_smdi_mwi_message_pop(struct ast_smdi_interface *iface)
00484 {
00485 return smdi_msg_pop(iface, SMDI_MWI);
00486 }
00487
00488 struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait(struct ast_smdi_interface *iface, int timeout)
00489 {
00490 struct ast_flags options = { 0 };
00491 return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options);
00492 }
00493
00494 struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait_station(struct ast_smdi_interface *iface, int timeout,
00495 const char *station)
00496 {
00497 struct ast_flags options = { 0 };
00498 return smdi_message_wait(iface, timeout, SMDI_MWI, station, options);
00499 }
00500
00501 struct ast_smdi_interface *ast_smdi_interface_find(const char *iface_name)
00502 {
00503 return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name));
00504 }
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 static void *smdi_read(void *iface_p)
00516 {
00517 struct ast_smdi_interface *iface = iface_p;
00518 struct ast_smdi_md_message *md_msg;
00519 struct ast_smdi_mwi_message *mwi_msg;
00520 char c = '\0';
00521 char *cp = NULL;
00522 int i;
00523 int start = 0;
00524
00525
00526 while ((c = fgetc(iface->file))) {
00527
00528
00529 if (!start) {
00530 if (c == 'M') {
00531 ast_log(LOG_DEBUG, "Read an 'M' to start an SMDI message\n");
00532 start = 1;
00533 }
00534 continue;
00535 }
00536
00537 if (c == 'D') {
00538 start = 0;
00539
00540 ast_log(LOG_DEBUG, "Read a 'D' ... it's an MD message.\n");
00541
00542 if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) {
00543 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00544 return NULL;
00545 }
00546
00547 ASTOBJ_INIT(md_msg);
00548
00549
00550 for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) {
00551 md_msg->mesg_desk_num[i] = fgetc(iface->file);
00552 ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_num[i]);
00553 }
00554
00555 md_msg->mesg_desk_num[sizeof(md_msg->mesg_desk_num) - 1] = '\0';
00556
00557 ast_log(LOG_DEBUG, "The message desk number is '%s'\n", md_msg->mesg_desk_num);
00558
00559
00560 for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) {
00561 md_msg->mesg_desk_term[i] = fgetc(iface->file);
00562 ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_term[i]);
00563 }
00564
00565 md_msg->mesg_desk_term[sizeof(md_msg->mesg_desk_term) - 1] = '\0';
00566
00567 ast_log(LOG_DEBUG, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term);
00568
00569
00570 md_msg->type = fgetc(iface->file);
00571
00572 ast_log(LOG_DEBUG, "Message type is '%c'\n", md_msg->type);
00573
00574
00575 cp = &md_msg->fwd_st[0];
00576 for (i = 0; i < sizeof(md_msg->fwd_st) - 1; i++) {
00577 if ((c = fgetc(iface->file)) == ' ') {
00578 *cp = '\0';
00579 ast_log(LOG_DEBUG, "Read a space, done looking for the forwarding station\n");
00580 break;
00581 }
00582
00583
00584 if (i >= iface->msdstrip) {
00585 ast_log(LOG_DEBUG, "Read a '%c' and stored it in the forwarding station buffer\n", c);
00586 *cp++ = c;
00587 } else {
00588 ast_log(LOG_DEBUG, "Read a '%c', but didn't store it in the fwd station buffer, because of the msdstrip setting (%d < %d)\n", c, i, iface->msdstrip);
00589 }
00590 }
00591
00592
00593 md_msg->fwd_st[sizeof(md_msg->fwd_st) - 1] = '\0';
00594 cp = NULL;
00595
00596 ast_log(LOG_DEBUG, "The forwarding station is '%s'\n", md_msg->fwd_st);
00597
00598
00599
00600 ast_copy_string(md_msg->name, md_msg->fwd_st, sizeof(md_msg->name));
00601
00602
00603 cp = &md_msg->calling_st[0];
00604 for (i = 0; i < sizeof(md_msg->calling_st) - 1; i++) {
00605 if (!isdigit((c = fgetc(iface->file)))) {
00606 *cp = '\0';
00607 ast_log(LOG_DEBUG, "Read a '%c', but didn't store it in the calling station buffer because it's not a digit\n", c);
00608 if (c == ' ') {
00609
00610
00611 i--;
00612 continue;
00613 }
00614 break;
00615 }
00616
00617
00618 if (i >= iface->msdstrip) {
00619 ast_log(LOG_DEBUG, "Read a '%c' and stored it in the calling station buffer\n", c);
00620 *cp++ = c;
00621 } else {
00622 ast_log(LOG_DEBUG, "Read a '%c', but didn't store it in the calling station buffer, because of the msdstrip setting (%d < %d)\n", c, i, iface->msdstrip);
00623 }
00624 }
00625
00626
00627 md_msg->calling_st[sizeof(md_msg->calling_st) - 1] = '\0';
00628 cp = NULL;
00629
00630 ast_log(LOG_DEBUG, "The calling station is '%s'\n", md_msg->calling_st);
00631
00632
00633 md_msg->timestamp = ast_tvnow();
00634 ast_smdi_md_message_push(iface, md_msg);
00635 ast_log(LOG_DEBUG, "Recieved SMDI MD message on %s\n", iface->name);
00636
00637 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
00638
00639 } else if (c == 'W') {
00640 start = 0;
00641
00642 ast_log(LOG_DEBUG, "Read a 'W', it's an MWI message. (No more debug coming for MWI messages)\n");
00643
00644 if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) {
00645 ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
00646 return NULL;
00647 }
00648
00649 ASTOBJ_INIT(mwi_msg);
00650
00651
00652 fgetc(iface->file);
00653
00654
00655 cp = &mwi_msg->fwd_st[0];
00656 for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) {
00657 if ((c = fgetc(iface->file)) == ' ') {
00658 *cp = '\0';
00659 break;
00660 }
00661
00662
00663 if (i >= iface->msdstrip)
00664 *cp++ = c;
00665 }
00666
00667
00668 mwi_msg->fwd_st[sizeof(mwi_msg->fwd_st) - 1] = '\0';
00669 cp = NULL;
00670
00671
00672
00673 ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name));
00674
00675
00676 for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++)
00677 mwi_msg->cause[i] = fgetc(iface->file);
00678
00679 mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0';
00680
00681
00682 mwi_msg->timestamp = ast_tvnow();
00683 ast_smdi_mwi_message_push(iface, mwi_msg);
00684 ast_log(LOG_DEBUG, "Recieved SMDI MWI message on %s\n", iface->name);
00685
00686 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
00687 } else {
00688 ast_log(LOG_ERROR, "Unknown SMDI message type recieved on %s (M%c).\n", iface->name, c);
00689 start = 0;
00690 }
00691 }
00692
00693 ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name);
00694 ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
00695 return NULL;
00696 }
00697
00698 void ast_smdi_md_message_destroy(struct ast_smdi_md_message *msg)
00699 {
00700 ast_free(msg);
00701 }
00702
00703 void ast_smdi_mwi_message_destroy(struct ast_smdi_mwi_message *msg)
00704 {
00705 ast_free(msg);
00706 }
00707
00708 static void destroy_mailbox_mapping(struct mailbox_mapping *mm)
00709 {
00710 ast_string_field_free_memory(mm);
00711 ASTOBJ_UNREF(mm->iface, ast_smdi_interface_destroy);
00712 free(mm);
00713 }
00714
00715 static void destroy_all_mailbox_mappings(void)
00716 {
00717 struct mailbox_mapping *mm;
00718
00719 ast_mutex_lock(&mwi_monitor.lock);
00720 while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry)))
00721 destroy_mailbox_mapping(mm);
00722 ast_mutex_unlock(&mwi_monitor.lock);
00723 }
00724
00725 static void append_mailbox_mapping(struct ast_variable *var, struct ast_smdi_interface *iface)
00726 {
00727 struct mailbox_mapping *mm;
00728 char *mailbox, *context;
00729
00730 if (!(mm = ast_calloc(1, sizeof(*mm))))
00731 return;
00732
00733 if (ast_string_field_init(mm, 32)) {
00734 free(mm);
00735 return;
00736 }
00737
00738 ast_string_field_set(mm, smdi, var->name);
00739
00740 context = ast_strdupa(var->value);
00741 mailbox = strsep(&context, "@");
00742 if (ast_strlen_zero(context))
00743 context = "default";
00744
00745 ast_string_field_set(mm, mailbox, mailbox);
00746 ast_string_field_set(mm, context, context);
00747
00748 mm->iface = ASTOBJ_REF(iface);
00749
00750 ast_mutex_lock(&mwi_monitor.lock);
00751 AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry);
00752 ast_mutex_unlock(&mwi_monitor.lock);
00753 }
00754
00755
00756
00757
00758 static void poll_mailbox(struct mailbox_mapping *mm)
00759 {
00760 char buf[1024];
00761 unsigned int state;
00762
00763 snprintf(buf, sizeof(buf), "%s@%s", mm->mailbox, mm->context);
00764
00765 state = !!ast_app_has_voicemail(mm->mailbox, NULL);
00766
00767 if (state != mm->cur_state) {
00768 if (state)
00769 ast_smdi_mwi_set(mm->iface, mm->smdi);
00770 else
00771 ast_smdi_mwi_unset(mm->iface, mm->smdi);
00772
00773 mm->cur_state = state;
00774 }
00775 }
00776
00777 static void *mwi_monitor_handler(void *data)
00778 {
00779 while (!mwi_monitor.stop) {
00780 struct timespec ts = { 0, };
00781 struct timeval polltime;
00782 struct mailbox_mapping *mm;
00783
00784 ast_mutex_lock(&mwi_monitor.lock);
00785
00786 mwi_monitor.last_poll = ast_tvnow();
00787
00788 AST_LIST_TRAVERSE(&mwi_monitor.mailbox_mappings, mm, entry)
00789 poll_mailbox(mm);
00790
00791
00792
00793 polltime = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0));
00794 ts.tv_sec = polltime.tv_sec;
00795 ts.tv_nsec = polltime.tv_usec * 1000;
00796 ast_cond_timedwait(&mwi_monitor.cond, &mwi_monitor.lock, &ts);
00797
00798 ast_mutex_unlock(&mwi_monitor.lock);
00799 }
00800
00801 return NULL;
00802 }
00803
00804 static struct ast_smdi_interface *alloc_smdi_interface(void)
00805 {
00806 struct ast_smdi_interface *iface;
00807
00808 if (!(iface = ast_calloc(1, sizeof(*iface))))
00809 return NULL;
00810
00811 ASTOBJ_INIT(iface);
00812 ASTOBJ_CONTAINER_INIT(&iface->md_q);
00813 ASTOBJ_CONTAINER_INIT(&iface->mwi_q);
00814
00815 ast_mutex_init(&iface->md_q_lock);
00816 ast_cond_init(&iface->md_q_cond, NULL);
00817
00818 ast_mutex_init(&iface->mwi_q_lock);
00819 ast_cond_init(&iface->mwi_q_cond, NULL);
00820
00821 return iface;
00822 }
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834 static int smdi_load(int reload)
00835 {
00836 struct ast_config *conf;
00837 struct ast_variable *v;
00838 struct ast_smdi_interface *iface = NULL;
00839 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00840 int res = 0;
00841
00842
00843 speed_t baud_rate = B9600;
00844 tcflag_t paritybit = PARENB;
00845 tcflag_t charsize = CS7;
00846 int stopbits = 0;
00847
00848 int msdstrip = 0;
00849 long msg_expiry = SMDI_MSG_EXPIRY_TIME;
00850
00851 if (!(conf = ast_config_load(config_file, config_flags))) {
00852 if (reload)
00853 ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file);
00854 else
00855 ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file);
00856 return 1;
00857 } else if (conf == CONFIG_STATUS_FILEUNCHANGED)
00858 return 0;
00859
00860
00861
00862
00863
00864
00865 if (reload)
00866 ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces);
00867
00868 for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) {
00869 if (!strcasecmp(v->name, "baudrate")) {
00870 if (!strcasecmp(v->value, "9600"))
00871 baud_rate = B9600;
00872 else if (!strcasecmp(v->value, "4800"))
00873 baud_rate = B4800;
00874 else if (!strcasecmp(v->value, "2400"))
00875 baud_rate = B2400;
00876 else if (!strcasecmp(v->value, "1200"))
00877 baud_rate = B1200;
00878 else {
00879 ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno);
00880 baud_rate = B9600;
00881 }
00882 } else if (!strcasecmp(v->name, "msdstrip")) {
00883 if (!sscanf(v->value, "%d", &msdstrip)) {
00884 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
00885 msdstrip = 0;
00886 } else if (0 > msdstrip || msdstrip > 9) {
00887 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
00888 msdstrip = 0;
00889 }
00890 } else if (!strcasecmp(v->name, "msgexpirytime")) {
00891 if (!sscanf(v->value, "%ld", &msg_expiry)) {
00892 ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno);
00893 msg_expiry = SMDI_MSG_EXPIRY_TIME;
00894 }
00895 } else if (!strcasecmp(v->name, "paritybit")) {
00896 if (!strcasecmp(v->value, "even"))
00897 paritybit = PARENB;
00898 else if (!strcasecmp(v->value, "odd"))
00899 paritybit = PARENB | PARODD;
00900 else if (!strcasecmp(v->value, "none"))
00901 paritybit = ~PARENB;
00902 else {
00903 ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno);
00904 paritybit = PARENB;
00905 }
00906 } else if (!strcasecmp(v->name, "charsize")) {
00907 if (!strcasecmp(v->value, "7"))
00908 charsize = CS7;
00909 else if (!strcasecmp(v->value, "8"))
00910 charsize = CS8;
00911 else {
00912 ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno);
00913 charsize = CS7;
00914 }
00915 } else if (!strcasecmp(v->name, "twostopbits")) {
00916 stopbits = ast_true(v->name);
00917 } else if (!strcasecmp(v->name, "smdiport")) {
00918 if (reload) {
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929 if ((iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) {
00930 ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name);
00931 ASTOBJ_UNMARK(iface);
00932 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00933 continue;
00934 }
00935 }
00936
00937 if (!(iface = alloc_smdi_interface()))
00938 continue;
00939
00940 ast_copy_string(iface->name, v->value, sizeof(iface->name));
00941
00942 iface->thread = AST_PTHREADT_NULL;
00943
00944 if (!(iface->file = fopen(iface->name, "r"))) {
00945 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno));
00946 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00947 continue;
00948 }
00949
00950 iface->fd = fileno(iface->file);
00951
00952
00953
00954
00955 if (tcgetattr(iface->fd, &iface->mode)) {
00956 ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno));
00957 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00958 continue;
00959 }
00960
00961
00962 if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) {
00963 ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno));
00964 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00965 continue;
00966 }
00967
00968
00969 if (stopbits)
00970 iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB;
00971 else
00972 iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB;
00973
00974
00975 iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit;
00976
00977
00978 iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize;
00979
00980
00981 if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) {
00982 ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno));
00983 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00984 continue;
00985 }
00986
00987
00988 iface->msdstrip = msdstrip;
00989
00990
00991 iface->msg_expiry = msg_expiry;
00992
00993
00994 ast_verb(3, "Starting SMDI monitor thread for %s\n", iface->name);
00995 if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) {
00996 ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name);
00997 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00998 continue;
00999 }
01000
01001 ASTOBJ_CONTAINER_LINK(&smdi_ifaces, iface);
01002 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
01003 ast_module_ref(ast_module_info->self);
01004 } else {
01005 ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file);
01006 }
01007 }
01008
01009 destroy_all_mailbox_mappings();
01010 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
01011
01012 iface = NULL;
01013
01014 for (v = ast_variable_browse(conf, "mailboxes"); v; v = v->next) {
01015 if (!strcasecmp(v->name, "smdiport")) {
01016 if (iface)
01017 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
01018
01019 if (!(iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) {
01020 ast_log(LOG_NOTICE, "SMDI interface %s not found\n", iface->name);
01021 continue;
01022 }
01023 } else if (!strcasecmp(v->name, "pollinginterval")) {
01024 if (sscanf(v->value, "%u", &mwi_monitor.polling_interval) != 1) {
01025 ast_log(LOG_ERROR, "Invalid value for pollinginterval: %s\n", v->value);
01026 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
01027 }
01028 } else {
01029 if (!iface) {
01030 ast_log(LOG_ERROR, "Mailbox mapping ignored, no valid SMDI interface specified in mailboxes section\n");
01031 continue;
01032 }
01033 append_mailbox_mapping(v, iface);
01034 }
01035 }
01036
01037 if (iface)
01038 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
01039
01040 ast_config_destroy(conf);
01041
01042 if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL
01043 && ast_pthread_create_background(&mwi_monitor.thread, NULL, mwi_monitor_handler, NULL)) {
01044 ast_log(LOG_ERROR, "Failed to start MWI monitoring thread. This module will not operate.\n");
01045 return AST_MODULE_LOAD_FAILURE;
01046 }
01047
01048
01049 if (reload)
01050 ASTOBJ_CONTAINER_PRUNE_MARKED(&smdi_ifaces, ast_smdi_interface_destroy);
01051
01052 ASTOBJ_CONTAINER_RDLOCK(&smdi_ifaces);
01053
01054 if (!smdi_ifaces.head)
01055 res = 1;
01056 ASTOBJ_CONTAINER_UNLOCK(&smdi_ifaces);
01057
01058 return res;
01059 }
01060
01061 struct smdi_msg_datastore {
01062 unsigned int id;
01063 struct ast_smdi_interface *iface;
01064 struct ast_smdi_md_message *md_msg;
01065 };
01066
01067 static void smdi_msg_datastore_destroy(void *data)
01068 {
01069 struct smdi_msg_datastore *smd = data;
01070
01071 if (smd->iface)
01072 ASTOBJ_UNREF(smd->iface, ast_smdi_interface_destroy);
01073
01074 if (smd->md_msg)
01075 ASTOBJ_UNREF(smd->md_msg, ast_smdi_md_message_destroy);
01076
01077 free(smd);
01078 }
01079
01080 static const struct ast_datastore_info smdi_msg_datastore_info = {
01081 .type = "SMDIMSG",
01082 .destroy = smdi_msg_datastore_destroy,
01083 };
01084
01085 static int smdi_msg_id;
01086
01087
01088 #define SMDI_RETRIEVE_TIMEOUT_DEFAULT 3000
01089
01090 AST_APP_OPTIONS(smdi_msg_ret_options, BEGIN_OPTIONS
01091 AST_APP_OPTION('t', OPT_SEARCH_TERMINAL),
01092 AST_APP_OPTION('n', OPT_SEARCH_NUMBER),
01093 END_OPTIONS );
01094
01095 static int smdi_msg_retrieve_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01096 {
01097 struct ast_module_user *u;
01098 AST_DECLARE_APP_ARGS(args,
01099 AST_APP_ARG(port);
01100 AST_APP_ARG(search_key);
01101 AST_APP_ARG(timeout);
01102 AST_APP_ARG(options);
01103 );
01104 struct ast_flags options = { 0 };
01105 unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
01106 int res = -1;
01107 char *parse = NULL;
01108 struct smdi_msg_datastore *smd = NULL;
01109 struct ast_datastore *datastore = NULL;
01110 struct ast_smdi_interface *iface = NULL;
01111 struct ast_smdi_md_message *md_msg = NULL;
01112
01113 u = ast_module_user_add(chan);
01114
01115 if (ast_strlen_zero(data)) {
01116 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE requires an argument\n");
01117 goto return_error;
01118 }
01119
01120 if (!chan) {
01121 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE must be used with a channel\n");
01122 goto return_error;
01123 }
01124
01125 ast_autoservice_start(chan);
01126
01127 parse = ast_strdupa(data);
01128 AST_STANDARD_APP_ARGS(args, parse);
01129
01130 if (ast_strlen_zero(args.port) || ast_strlen_zero(args.search_key)) {
01131 ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n");
01132 goto return_error;
01133 }
01134
01135 if (!(iface = ast_smdi_interface_find(args.port))) {
01136 ast_log(LOG_ERROR, "SMDI port '%s' not found\n", args.port);
01137 goto return_error;
01138 }
01139
01140 if (!ast_strlen_zero(args.options)) {
01141 ast_app_parse_options(smdi_msg_ret_options, &options, NULL, args.options);
01142 }
01143
01144 if (!ast_strlen_zero(args.timeout)) {
01145 if (sscanf(args.timeout, "%u", &timeout) != 1) {
01146 ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout);
01147 timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
01148 }
01149 }
01150
01151 if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.search_key, options))) {
01152 ast_log(LOG_WARNING, "No SMDI message retrieved for search key '%s' after "
01153 "waiting %u ms.\n", args.search_key, timeout);
01154 goto return_error;
01155 }
01156
01157 if (!(smd = ast_calloc(1, sizeof(*smd))))
01158 goto return_error;
01159
01160 smd->iface = ASTOBJ_REF(iface);
01161 smd->md_msg = ASTOBJ_REF(md_msg);
01162 smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1);
01163 snprintf(buf, len, "%u", smd->id);
01164
01165 if (!(datastore = ast_datastore_alloc(&smdi_msg_datastore_info, buf)))
01166 goto return_error;
01167
01168 datastore->data = smd;
01169
01170 ast_channel_lock(chan);
01171 ast_channel_datastore_add(chan, datastore);
01172 ast_channel_unlock(chan);
01173
01174 res = 0;
01175
01176 return_error:
01177 if (iface)
01178 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
01179
01180 if (md_msg)
01181 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
01182
01183 if (smd && !datastore)
01184 smdi_msg_datastore_destroy(smd);
01185
01186 if (parse)
01187 ast_autoservice_stop(chan);
01188
01189 ast_module_user_remove(u);
01190
01191 return res;
01192 }
01193
01194 static int smdi_msg_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01195 {
01196 struct ast_module_user *u;
01197 int res = -1;
01198 AST_DECLARE_APP_ARGS(args,
01199 AST_APP_ARG(id);
01200 AST_APP_ARG(component);
01201 );
01202 char *parse;
01203 struct ast_datastore *datastore = NULL;
01204 struct smdi_msg_datastore *smd = NULL;
01205
01206 u = ast_module_user_add(chan);
01207
01208 if (!chan) {
01209 ast_log(LOG_ERROR, "SMDI_MSG can not be called without a channel\n");
01210 goto return_error;
01211 }
01212
01213 if (ast_strlen_zero(data)) {
01214 ast_log(LOG_WARNING, "SMDI_MSG requires an argument\n");
01215 goto return_error;
01216 }
01217
01218 parse = ast_strdupa(data);
01219 AST_STANDARD_APP_ARGS(args, parse);
01220
01221 if (ast_strlen_zero(args.id)) {
01222 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
01223 goto return_error;
01224 }
01225
01226 if (ast_strlen_zero(args.component)) {
01227 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
01228 goto return_error;
01229 }
01230
01231 ast_channel_lock(chan);
01232 datastore = ast_channel_datastore_find(chan, &smdi_msg_datastore_info, args.id);
01233 ast_channel_unlock(chan);
01234
01235 if (!datastore) {
01236 ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id);
01237 goto return_error;
01238 }
01239
01240 smd = datastore->data;
01241
01242 if (!strcasecmp(args.component, "number")) {
01243 ast_copy_string(buf, smd->md_msg->mesg_desk_num, len);
01244 } else if (!strcasecmp(args.component, "terminal")) {
01245 ast_copy_string(buf, smd->md_msg->mesg_desk_term, len);
01246 } else if (!strcasecmp(args.component, "station")) {
01247 ast_copy_string(buf, smd->md_msg->fwd_st, len);
01248 } else if (!strcasecmp(args.component, "callerid")) {
01249 ast_copy_string(buf, smd->md_msg->calling_st, len);
01250 } else if (!strcasecmp(args.component, "type")) {
01251 snprintf(buf, len, "%c", smd->md_msg->type);
01252 } else {
01253 ast_log(LOG_ERROR, "'%s' is not a valid message component for SMDI_MSG\n",
01254 args.component);
01255 goto return_error;
01256 }
01257
01258 res = 0;
01259
01260 return_error:
01261 ast_module_user_remove(u);
01262
01263 return res;
01264 }
01265
01266 static struct ast_custom_function smdi_msg_retrieve_function = {
01267 .name = "SMDI_MSG_RETRIEVE",
01268 .synopsis = "Retrieve an SMDI message.",
01269 .syntax = "SMDI_MSG_RETRIEVE(<smdi port>,<search key>[,timeout[,options]])",
01270 .desc =
01271 " This function is used to retrieve an incoming SMDI message. It returns\n"
01272 "an ID which can be used with the SMDI_MSG() function to access details of\n"
01273 "the message. Note that this is a destructive function in the sense that\n"
01274 "once an SMDI message is retrieved using this function, it is no longer in\n"
01275 "the global SMDI message queue, and can not be accessed by any other Asterisk\n"
01276 "channels. The timeout for this function is optional, and the default is\n"
01277 "3 seconds. When providing a timeout, it should be in milliseconds.\n"
01278 " The default search is done on the forwarding station ID. However, if\n"
01279 "you set one of the search key options in the options field, you can change\n"
01280 "this behavior.\n"
01281 " Options:\n"
01282 " t - Instead of searching on the forwarding station, search on the message\n"
01283 " desk terminal.\n"
01284 " n - Instead of searching on the forwarding station, search on the message\n"
01285 " desk number.\n"
01286 "",
01287 .read = smdi_msg_retrieve_read,
01288 };
01289
01290 static struct ast_custom_function smdi_msg_function = {
01291 .name = "SMDI_MSG",
01292 .synopsis = "Retrieve details about an SMDI message.",
01293 .syntax = "SMDI_MSG(<message_id>,<component>)",
01294 .desc =
01295 " This function is used to access details of an SMDI message that was\n"
01296 "pulled from the incoming SMDI message queue using the SMDI_MSG_RETRIEVE()\n"
01297 "function.\n"
01298 " Valid message components are:\n"
01299 " number - The message desk number\n"
01300 " terminal - The message desk terminal\n"
01301 " station - The forwarding station\n"
01302 " callerid - The callerID of the calling party that was forwarded\n"
01303 " type - The call type. The value here is the exact character\n"
01304 " that came in on the SMDI link. Typically, example values\n"
01305 " are: D - Direct Calls, A - Forward All Calls,\n"
01306 " B - Forward Busy Calls, N - Forward No Answer Calls\n"
01307 "",
01308 .read = smdi_msg_read,
01309 };
01310
01311 static int load_module(void)
01312 {
01313 int res;
01314
01315
01316 memset(&smdi_ifaces, 0, sizeof(smdi_ifaces));
01317 ASTOBJ_CONTAINER_INIT(&smdi_ifaces);
01318
01319 ast_mutex_init(&mwi_monitor.lock);
01320 ast_cond_init(&mwi_monitor.cond, NULL);
01321
01322 ast_custom_function_register(&smdi_msg_retrieve_function);
01323 ast_custom_function_register(&smdi_msg_function);
01324
01325
01326 res = smdi_load(0);
01327 if (res < 0) {
01328 return res;
01329 } else if (res == 1) {
01330 ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n");
01331 return AST_MODULE_LOAD_DECLINE;
01332 }
01333
01334 return AST_MODULE_LOAD_SUCCESS;
01335 }
01336
01337 static int unload_module(void)
01338 {
01339
01340 ASTOBJ_CONTAINER_DESTROYALL(&smdi_ifaces, ast_smdi_interface_destroy);
01341 ASTOBJ_CONTAINER_DESTROY(&smdi_ifaces);
01342
01343 destroy_all_mailbox_mappings();
01344
01345 ast_mutex_lock(&mwi_monitor.lock);
01346 mwi_monitor.stop = 1;
01347 ast_cond_signal(&mwi_monitor.cond);
01348 ast_mutex_unlock(&mwi_monitor.lock);
01349
01350 if (mwi_monitor.thread != AST_PTHREADT_NULL) {
01351 pthread_join(mwi_monitor.thread, NULL);
01352 }
01353
01354 ast_custom_function_unregister(&smdi_msg_retrieve_function);
01355 ast_custom_function_unregister(&smdi_msg_function);
01356
01357 return 0;
01358 }
01359
01360 static int reload(void)
01361 {
01362 int res;
01363
01364 res = smdi_load(1);
01365
01366 if (res < 0) {
01367 return res;
01368 } else if (res == 1) {
01369 ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n");
01370 return 0;
01371 } else
01372 return 0;
01373 }
01374
01375 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Simplified Message Desk Interface (SMDI) Resource",
01376 .load = load_module,
01377 .unload = unload_module,
01378 .reload = reload,
01379 );