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