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