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