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