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