00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include "asterisk.h"
00054
00055 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 316707 $")
00056
00057 #include <stdlib.h>
00058 #include <errno.h>
00059 #include <unistd.h>
00060 #include <string.h>
00061 #include <stdlib.h>
00062 #include <stdio.h>
00063 #include <sys/time.h>
00064 #include <sys/stat.h>
00065 #include <sys/types.h>
00066 #include <sys/mman.h>
00067 #include <time.h>
00068 #include <dirent.h>
00069 #ifdef IMAP_STORAGE
00070 #include <ctype.h>
00071 #include <signal.h>
00072 #include <pwd.h>
00073 #ifdef USE_SYSTEM_IMAP
00074 #include <imap/c-client.h>
00075 #include <imap/imap4r1.h>
00076 #include <imap/linkage.h>
00077 #elif defined (USE_SYSTEM_CCLIENT)
00078 #include <c-client/c-client.h>
00079 #include <c-client/imap4r1.h>
00080 #include <c-client/linkage.h>
00081 #else
00082 #include "c-client.h"
00083 #include "imap4r1.h"
00084 #include "linkage.h"
00085 #endif
00086 #endif
00087 #include "asterisk/lock.h"
00088 #include "asterisk/file.h"
00089 #include "asterisk/logger.h"
00090 #include "asterisk/channel.h"
00091 #include "asterisk/pbx.h"
00092 #include "asterisk/options.h"
00093 #include "asterisk/config.h"
00094 #include "asterisk/say.h"
00095 #include "asterisk/module.h"
00096 #include "asterisk/adsi.h"
00097 #include "asterisk/app.h"
00098 #include "asterisk/manager.h"
00099 #include "asterisk/dsp.h"
00100 #include "asterisk/localtime.h"
00101 #include "asterisk/cli.h"
00102 #include "asterisk/utils.h"
00103 #include "asterisk/stringfields.h"
00104 #include "asterisk/smdi.h"
00105 #include "asterisk/astobj2.h"
00106 #ifdef ODBC_STORAGE
00107 #include "asterisk/res_odbc.h"
00108 #endif
00109
00110 #ifdef IMAP_STORAGE
00111 #include "asterisk/threadstorage.h"
00112
00113 AST_MUTEX_DEFINE_STATIC(imaptemp_lock);
00114 static char imaptemp[1024];
00115 static char imapserver[48];
00116 static char imapport[8];
00117 static char imapflags[128];
00118 static char imapfolder[64];
00119 static char authuser[32];
00120 static char authpassword[42];
00121 static int imapversion = 1;
00122
00123 static int expungeonhangup = 1;
00124 static char delimiter = '\0';
00125 static const long DEFAULT_IMAP_TCP_TIMEOUT = 60L;
00126
00127 struct vm_state;
00128 struct ast_vm_user;
00129
00130 AST_THREADSTORAGE(ts_vmstate, ts_vmstate_init);
00131
00132 static int init_mailstream (struct vm_state *vms, int box);
00133 static void write_file (char *filename, char *buffer, unsigned long len);
00134
00135 static char *get_header_by_tag(char *header, char *tag);
00136 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00137 static char *get_user_by_mailbox(char *mailbox);
00138 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive);
00139 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00140 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00141 static void vmstate_insert(struct vm_state *vms);
00142 static void vmstate_delete(struct vm_state *vms);
00143 static void set_update(MAILSTREAM * stream);
00144 static void init_vm_state(struct vm_state *vms);
00145 static void copy_msgArray(struct vm_state *dst, struct vm_state *src);
00146 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format);
00147 static void get_mailbox_delimiter(MAILSTREAM *stream);
00148 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00149 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00150 static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms);
00151 static void check_quota(struct vm_state *vms, char *mailbox);
00152 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box);
00153 struct vmstate {
00154 struct vm_state *vms;
00155 struct vmstate *next;
00156 };
00157 AST_MUTEX_DEFINE_STATIC(vmstate_lock);
00158 static struct vmstate *vmstates = NULL;
00159 #endif
00160
00161 #define SMDI_MWI_WAIT_TIMEOUT 1000
00162
00163 #define COMMAND_TIMEOUT 5000
00164
00165 #define VOICEMAIL_DIR_MODE 0777
00166 #define VOICEMAIL_FILE_MODE 0666
00167 #define CHUNKSIZE 65536
00168
00169 #define VOICEMAIL_CONFIG "voicemail.conf"
00170 #define ASTERISK_USERNAME "asterisk"
00171
00172
00173
00174 #define SENDMAIL "/usr/sbin/sendmail -t"
00175
00176 #define INTRO "vm-intro"
00177
00178 #define MAXMSG 100
00179 #ifndef IMAP_STORAGE
00180 #define MAXMSGLIMIT 9999
00181 #else
00182 #define MAXMSGLIMIT 255
00183 #endif
00184
00185 #define BASEMAXINLINE 256
00186 #define BASELINELEN 72
00187 #define BASEMAXINLINE 256
00188 #ifdef IMAP_STORAGE
00189 #define ENDL "\r\n"
00190 #else
00191 #define ENDL "\n"
00192 #endif
00193
00194 #define MAX_DATETIME_FORMAT 512
00195 #define MAX_NUM_CID_CONTEXTS 10
00196
00197 #define VM_REVIEW (1 << 0)
00198 #define VM_OPERATOR (1 << 1)
00199 #define VM_SAYCID (1 << 2)
00200 #define VM_SVMAIL (1 << 3)
00201 #define VM_ENVELOPE (1 << 4)
00202 #define VM_SAYDURATION (1 << 5)
00203 #define VM_SKIPAFTERCMD (1 << 6)
00204 #define VM_FORCENAME (1 << 7)
00205 #define VM_FORCEGREET (1 << 8)
00206 #define VM_PBXSKIP (1 << 9)
00207 #define VM_DIRECFORWARD (1 << 10)
00208 #define VM_ATTACH (1 << 11)
00209 #define VM_DELETE (1 << 12)
00210 #define VM_ALLOCED (1 << 13)
00211 #define VM_SEARCH (1 << 14)
00212 #define VM_TEMPGREETWARN (1 << 15)
00213 #define ERROR_LOCK_PATH -100
00214 #define ERROR_MAILBOX_FULL -200
00215 #define OPERATOR_EXIT 300
00216
00217
00218 enum {
00219 OPT_SILENT = (1 << 0),
00220 OPT_BUSY_GREETING = (1 << 1),
00221 OPT_UNAVAIL_GREETING = (1 << 2),
00222 OPT_RECORDGAIN = (1 << 3),
00223 OPT_PREPEND_MAILBOX = (1 << 4),
00224 OPT_PRIORITY_JUMP = (1 << 5),
00225 OPT_AUTOPLAY = (1 << 6),
00226 } vm_option_flags;
00227
00228 enum {
00229 OPT_ARG_RECORDGAIN = 0,
00230 OPT_ARG_PLAYFOLDER = 1,
00231
00232 OPT_ARG_ARRAY_SIZE = 2,
00233 } vm_option_args;
00234
00235 AST_APP_OPTIONS(vm_app_options, {
00236 AST_APP_OPTION('s', OPT_SILENT),
00237 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00238 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00239 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00240 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00241 AST_APP_OPTION('j', OPT_PRIORITY_JUMP),
00242 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00243 });
00244
00245 static int load_config(void);
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 struct baseio {
00329 int iocp;
00330 int iolen;
00331 int linelength;
00332 int ateof;
00333 unsigned char iobuf[BASEMAXINLINE];
00334 };
00335
00336
00337 struct ast_vm_user {
00338 char context[AST_MAX_CONTEXT];
00339 char mailbox[AST_MAX_EXTENSION];
00340 char password[80];
00341 char fullname[80];
00342 char email[80];
00343 char pager[80];
00344 char serveremail[80];
00345 char mailcmd[160];
00346 char preprocesscmd[160];
00347 char preprocessfmt[20];
00348 char language[MAX_LANGUAGE];
00349 char zonetag[80];
00350 char callback[80];
00351 char dialout[80];
00352 char uniqueid[80];
00353 char exit[80];
00354 char attachfmt[20];
00355 unsigned int flags;
00356 int saydurationm;
00357 int maxmsg;
00358 #ifdef IMAP_STORAGE
00359 char imapuser[80];
00360 char imappassword[80];
00361 char imapvmshareid[80];
00362 int imapversion;
00363 #endif
00364 double volgain;
00365 AST_LIST_ENTRY(ast_vm_user) list;
00366 };
00367
00368 struct vm_zone {
00369 AST_LIST_ENTRY(vm_zone) list;
00370 char name[80];
00371 char timezone[80];
00372 char msg_format[512];
00373 };
00374
00375 struct vm_state {
00376 char curbox[80];
00377 char username[80];
00378 char context[80];
00379 char curdir[PATH_MAX];
00380 char vmbox[PATH_MAX];
00381 char fn[PATH_MAX];
00382 char fn2[PATH_MAX];
00383 int *deleted;
00384 int *heard;
00385 int dh_arraysize;
00386 int curmsg;
00387 int lastmsg;
00388 int newmessages;
00389 int oldmessages;
00390 int starting;
00391 int repeats;
00392 #ifdef IMAP_STORAGE
00393 ast_mutex_t lock;
00394 int updated;
00395 long msgArray[256];
00396 MAILSTREAM *mailstream;
00397 int vmArrayIndex;
00398 char imapuser[80];
00399 int imapversion;
00400 int interactive;
00401 unsigned int quota_limit;
00402 unsigned int quota_usage;
00403 struct vm_state *persist_vms;
00404 #endif
00405 };
00406 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain);
00407 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00408 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00409 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00410 signed char record_gain, struct vm_state *vms);
00411 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00412 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00413 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname);
00414 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *folder, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap);
00415 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00416 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00417 #endif
00418 static void apply_options(struct ast_vm_user *vmu, const char *options);
00419
00420 struct ao2_container *inprocess_container;
00421
00422 struct inprocess {
00423 int count;
00424 char *context;
00425 char mailbox[0];
00426 };
00427
00428 static int inprocess_hash_fn(const void *obj, const int flags)
00429 {
00430 const struct inprocess *i = obj;
00431 return atoi(i->mailbox);
00432 }
00433
00434 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00435 {
00436 struct inprocess *i = obj, *j = arg;
00437 if (strcmp(i->mailbox, j->mailbox)) {
00438 return 0;
00439 }
00440 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00441 }
00442
00443 static int inprocess_count(const char *context, const char *mailbox, int delta)
00444 {
00445 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00446 arg->context = arg->mailbox + strlen(mailbox) + 1;
00447 strcpy(arg->mailbox, mailbox);
00448 strcpy(arg->context, context);
00449 ao2_lock(inprocess_container);
00450 if ((i = ao2_find(inprocess_container, arg, 0))) {
00451 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00452 ao2_unlock(inprocess_container);
00453 ao2_ref(i, -1);
00454 return ret;
00455 }
00456 if (delta < 0) {
00457 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00458 }
00459 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00460 ao2_unlock(inprocess_container);
00461 return 0;
00462 }
00463 i->context = i->mailbox + strlen(mailbox) + 1;
00464 strcpy(i->mailbox, mailbox);
00465 strcpy(i->context, context);
00466 i->count = delta;
00467 ao2_link(inprocess_container, i);
00468 ao2_unlock(inprocess_container);
00469 ao2_ref(i, -1);
00470 return 0;
00471 }
00472
00473 #ifdef ODBC_STORAGE
00474 static char odbc_database[80];
00475 static char odbc_table[80];
00476 #define RETRIEVE(a,b,c) retrieve_file(a,b)
00477 #define DISPOSE(a,b) remove_file(a,b)
00478 #define STORE(a,b,c,d,e,f,g,h,i) store_file(a,b,c,d)
00479 #define EXISTS(a,b,c,d) (message_exists(a,b))
00480 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00481 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00482 #define DELETE(a,b,c,d) (delete_file(a,b))
00483 #else
00484 #ifdef IMAP_STORAGE
00485 #define RETRIEVE(a,b,c) imap_retrieve_file(a,b,c)
00486 #define DISPOSE(a,b) remove_file(a,b)
00487 #define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i))
00488 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00489 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00490 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00491 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00492 #else
00493 #define RETRIEVE(a,b,c)
00494 #define DISPOSE(a,b)
00495 #define STORE(a,b,c,d,e,f,g,h,i)
00496 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00497 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00498 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00499 #define DELETE(a,b,c,d) (vm_delete(c))
00500 #endif
00501 #endif
00502
00503 static char VM_SPOOL_DIR[PATH_MAX];
00504
00505 static char ext_pass_cmd[128];
00506
00507 static int my_umask;
00508
00509 #if ODBC_STORAGE
00510 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00511 #elif IMAP_STORAGE
00512 #define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00513 #else
00514 #define tdesc "Comedian Mail (Voicemail System)"
00515 #endif
00516
00517 static char userscontext[AST_MAX_EXTENSION] = "default";
00518
00519 static char *addesc = "Comedian Mail";
00520
00521 static char *synopsis_vm =
00522 "Leave a Voicemail message";
00523
00524 static char *descrip_vm =
00525 " VoiceMail(mailbox[@context][&mailbox[@context]][...][|options]): This\n"
00526 "application allows the calling party to leave a message for the specified\n"
00527 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
00528 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
00529 "specified mailbox does not exist.\n"
00530 " The Voicemail application will exit if any of the following DTMF digits are\n"
00531 "received:\n"
00532 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
00533 " * - Jump to the 'a' extension in the current dialplan context.\n"
00534 " This application will set the following channel variable upon completion:\n"
00535 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
00536 " application. The possible values are:\n"
00537 " SUCCESS | USEREXIT | FAILED\n\n"
00538 " Options:\n"
00539 " b - Play the 'busy' greeting to the calling party.\n"
00540 " g(#) - Use the specified amount of gain when recording the voicemail\n"
00541 " message. The units are whole-number decibels (dB).\n"
00542 " Only works on supported technologies, which is Zap only.\n"
00543 " s - Skip the playback of instructions for leaving a message to the\n"
00544 " calling party.\n"
00545 " u - Play the 'unavailable' greeting.\n"
00546 " j - Jump to priority n+101 if the mailbox is not found or some other\n"
00547 " error occurs.\n";
00548
00549 static char *synopsis_vmain =
00550 "Check Voicemail messages";
00551
00552 static char *descrip_vmain =
00553 " VoiceMailMain([mailbox][@context][|options]): This application allows the\n"
00554 "calling party to check voicemail messages. A specific mailbox, and optional\n"
00555 "corresponding context, may be specified. If a mailbox is not provided, the\n"
00556 "calling party will be prompted to enter one. If a context is not specified,\n"
00557 "the 'default' context will be used.\n\n"
00558 " Options:\n"
00559 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
00560 " is entered by the caller.\n"
00561 " g(#) - Use the specified amount of gain when recording a voicemail\n"
00562 " message. The units are whole-number decibels (dB).\n"
00563 " s - Skip checking the passcode for the mailbox.\n"
00564 " a(#) - Skip folder prompt and go directly to folder specified.\n"
00565 " Defaults to INBOX\n";
00566
00567 static char *synopsis_vm_box_exists =
00568 "Check to see if Voicemail mailbox exists";
00569
00570 static char *descrip_vm_box_exists =
00571 " MailboxExists(mailbox[@context][|options]): Check to see if the specified\n"
00572 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
00573 "will be used.\n"
00574 " This application will set the following channel variable upon completion:\n"
00575 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
00576 " MailboxExists application. Possible values include:\n"
00577 " SUCCESS | FAILED\n\n"
00578 " Options:\n"
00579 " j - Jump to priority n+101 if the mailbox is found.\n";
00580
00581 static char *synopsis_vmauthenticate =
00582 "Authenticate with Voicemail passwords";
00583
00584 static char *descrip_vmauthenticate =
00585 " VMAuthenticate([mailbox][@context][|options]): This application behaves the\n"
00586 "same way as the Authenticate application, but the passwords are taken from\n"
00587 "voicemail.conf.\n"
00588 " If the mailbox is specified, only that mailbox's password will be considered\n"
00589 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
00590 "be set with the authenticated mailbox.\n\n"
00591 " Options:\n"
00592 " s - Skip playing the initial prompts.\n";
00593
00594
00595 static char *app = "VoiceMail";
00596
00597
00598 static char *app2 = "VoiceMailMain";
00599
00600 static char *app3 = "MailboxExists";
00601 static char *app4 = "VMAuthenticate";
00602
00603 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00604 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00605 static char zonetag[80];
00606 static int maxsilence;
00607 static int maxmsg;
00608 static int silencethreshold = 128;
00609 static char serveremail[80];
00610 static char mailcmd[160];
00611 static char preprocesscmd[160];
00612 static char preprocessfmt[20];
00613 static char externnotify[160];
00614 static struct ast_smdi_interface *smdi_iface = NULL;
00615 static char vmfmts[80];
00616 static double volgain;
00617 static int vmminmessage;
00618 static int vmmaxmessage;
00619 static int maxgreet;
00620 static int skipms;
00621 static int maxlogins;
00622
00623 static struct ast_flags globalflags = {0};
00624
00625 static int saydurationminfo;
00626
00627 static char dialcontext[AST_MAX_CONTEXT];
00628 static char callcontext[AST_MAX_CONTEXT];
00629 static char exitcontext[AST_MAX_CONTEXT];
00630
00631 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00632
00633
00634 static char *emailbody = NULL;
00635 static char *emailsubject = NULL;
00636 static char *pagerbody = NULL;
00637 static char *pagersubject = NULL;
00638 static char fromstring[100];
00639 static char pagerfromstring[100];
00640 static char emailtitle[100];
00641 static char charset[32] = "ISO-8859-1";
00642
00643 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00644 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00645 static int adsiver = 1;
00646 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00647
00648
00649
00650
00651
00652
00653
00654
00655 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00656 {
00657 char *bufptr = buf;
00658 for (; *input; input++) {
00659 if (*input < 32) {
00660 continue;
00661 }
00662 *bufptr++ = *input;
00663 if (bufptr == buf + buflen - 1) {
00664 break;
00665 }
00666 }
00667 *bufptr = '\0';
00668 return buf;
00669 }
00670
00671 static void populate_defaults(struct ast_vm_user *vmu)
00672 {
00673 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00674 if (saydurationminfo)
00675 vmu->saydurationm = saydurationminfo;
00676 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
00677 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
00678 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
00679 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
00680 if (maxmsg)
00681 vmu->maxmsg = maxmsg;
00682 vmu->volgain = volgain;
00683 }
00684
00685 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
00686 {
00687 int x;
00688 if (!strcasecmp(var, "attach")) {
00689 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
00690 } else if (!strcasecmp(var, "attachfmt")) {
00691 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
00692 } else if (!strcasecmp(var, "preprocesscmd")) {
00693 ast_copy_string(vmu->preprocesscmd, value, sizeof(vmu->preprocesscmd));
00694 } else if (!strcasecmp(var, "preprocessfmt")) {
00695 ast_copy_string(vmu->preprocessfmt, value, sizeof(vmu->preprocessfmt));
00696 } else if (!strcasecmp(var, "serveremail")) {
00697 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
00698 } else if (!strcasecmp(var, "language")) {
00699 ast_copy_string(vmu->language, value, sizeof(vmu->language));
00700 } else if (!strcasecmp(var, "tz")) {
00701 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
00702 #ifdef IMAP_STORAGE
00703 } else if (!strcasecmp(var, "imapuser")) {
00704 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
00705 vmu->imapversion = imapversion;
00706 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
00707 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
00708 vmu->imapversion = imapversion;
00709 } else if (!strcasecmp(var, "imapvmshareid")) {
00710 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
00711 vmu->imapversion = imapversion;
00712 #endif
00713 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
00714 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
00715 } else if (!strcasecmp(var, "saycid")){
00716 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
00717 } else if (!strcasecmp(var,"sendvoicemail")){
00718 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
00719 } else if (!strcasecmp(var, "review")){
00720 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
00721 } else if (!strcasecmp(var, "tempgreetwarn")){
00722 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
00723 } else if (!strcasecmp(var, "operator")){
00724 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
00725 } else if (!strcasecmp(var, "envelope")){
00726 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
00727 } else if (!strcasecmp(var, "sayduration")){
00728 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
00729 } else if (!strcasecmp(var, "saydurationm")){
00730 if (sscanf(value, "%30d", &x) == 1) {
00731 vmu->saydurationm = x;
00732 } else {
00733 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
00734 }
00735 } else if (!strcasecmp(var, "forcename")){
00736 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
00737 } else if (!strcasecmp(var, "forcegreetings")){
00738 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
00739 } else if (!strcasecmp(var, "callback")) {
00740 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
00741 } else if (!strcasecmp(var, "dialout")) {
00742 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
00743 } else if (!strcasecmp(var, "exitcontext")) {
00744 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
00745 } else if (!strcasecmp(var, "maxmsg")) {
00746 vmu->maxmsg = atoi(value);
00747 if (vmu->maxmsg <= 0) {
00748 ast_log(LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %i\n", value, MAXMSG);
00749 vmu->maxmsg = MAXMSG;
00750 } else if (vmu->maxmsg > MAXMSGLIMIT) {
00751 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
00752 vmu->maxmsg = MAXMSGLIMIT;
00753 }
00754 } else if (!strcasecmp(var, "volgain")) {
00755 sscanf(value, "%30lf", &vmu->volgain);
00756 } else if (!strcasecmp(var, "options")) {
00757 apply_options(vmu, value);
00758 }
00759 }
00760
00761 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
00762 {
00763 int res = -1;
00764 if (!strcmp(vmu->password, password)) {
00765
00766 res = 0;
00767 } else if (!ast_strlen_zero(vmu->uniqueid)) {
00768 if (ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, NULL) > 0) {
00769 ast_copy_string(vmu->password, password, sizeof(vmu->password));
00770 res = 0;
00771 }
00772 }
00773 return res;
00774 }
00775
00776 static void apply_options(struct ast_vm_user *vmu, const char *options)
00777 {
00778 char *stringp;
00779 char *s;
00780 char *var, *value;
00781 stringp = ast_strdupa(options);
00782 while ((s = strsep(&stringp, "|"))) {
00783 value = s;
00784 if ((var = strsep(&value, "=")) && value) {
00785 apply_option(vmu, var, value);
00786 }
00787 }
00788 }
00789
00790 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
00791 {
00792 struct ast_variable *tmp;
00793 tmp = var;
00794 while (tmp) {
00795 if (!strcasecmp(tmp->name, "vmsecret")) {
00796 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00797 } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) {
00798 if (ast_strlen_zero(retval->password))
00799 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00800 } else if (!strcasecmp(tmp->name, "uniqueid")) {
00801 ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
00802 } else if (!strcasecmp(tmp->name, "pager")) {
00803 ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
00804 } else if (!strcasecmp(tmp->name, "email")) {
00805 ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
00806 } else if (!strcasecmp(tmp->name, "fullname")) {
00807 ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
00808 } else if (!strcasecmp(tmp->name, "context")) {
00809 ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
00810 #ifdef IMAP_STORAGE
00811 } else if (!strcasecmp(tmp->name, "imapuser")) {
00812 ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
00813 retval->imapversion = imapversion;
00814 } else if (!strcasecmp(tmp->name, "imappassword") || !strcasecmp(tmp->name, "imapsecret")) {
00815 ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
00816 retval->imapversion = imapversion;
00817 } else if (!strcasecmp(tmp->name, "imapvmshareid")) {
00818 ast_copy_string(retval->imapvmshareid, tmp->value, sizeof(retval->imapvmshareid));
00819 retval->imapversion = imapversion;
00820 #endif
00821 } else
00822 apply_option(retval, tmp->name, tmp->value);
00823 tmp = tmp->next;
00824 }
00825 }
00826
00827 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00828 {
00829 struct ast_variable *var;
00830 struct ast_vm_user *retval;
00831
00832 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
00833 if (!ivm)
00834 ast_set_flag(retval, VM_ALLOCED);
00835 else
00836 memset(retval, 0, sizeof(*retval));
00837 if (mailbox)
00838 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
00839 populate_defaults(retval);
00840 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
00841 var = ast_load_realtime("voicemail", "mailbox", mailbox, NULL);
00842 else
00843 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, NULL);
00844 if (var) {
00845 apply_options_full(retval, var);
00846 ast_variables_destroy(var);
00847 } else {
00848 if (!ivm)
00849 free(retval);
00850 retval = NULL;
00851 }
00852 }
00853 return retval;
00854 }
00855
00856 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00857 {
00858
00859 struct ast_vm_user *vmu=NULL, *cur;
00860 AST_LIST_LOCK(&users);
00861
00862 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
00863 context = "default";
00864
00865 AST_LIST_TRAVERSE(&users, cur, list) {
00866 #ifdef IMAP_STORAGE
00867 if (cur->imapversion != imapversion) {
00868 continue;
00869 }
00870 #endif
00871 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
00872 break;
00873 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
00874 break;
00875 }
00876 if (cur) {
00877
00878 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
00879 memcpy(vmu, cur, sizeof(*vmu));
00880 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
00881 AST_LIST_NEXT(vmu, list) = NULL;
00882 }
00883 } else
00884 vmu = find_user_realtime(ivm, context, mailbox);
00885 AST_LIST_UNLOCK(&users);
00886 return vmu;
00887 }
00888
00889 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
00890 {
00891
00892 struct ast_vm_user *cur;
00893 int res = -1;
00894 AST_LIST_LOCK(&users);
00895 AST_LIST_TRAVERSE(&users, cur, list) {
00896 if ((!context || !strcasecmp(context, cur->context)) &&
00897 (!strcasecmp(mailbox, cur->mailbox)))
00898 break;
00899 }
00900 if (cur) {
00901 ast_copy_string(cur->password, newpass, sizeof(cur->password));
00902 res = 0;
00903 }
00904 AST_LIST_UNLOCK(&users);
00905 return res;
00906 }
00907
00908 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
00909 {
00910 struct ast_config *cfg=NULL;
00911 struct ast_variable *var=NULL;
00912 struct ast_category *cat=NULL;
00913 char *category=NULL, *value=NULL, *new=NULL;
00914 const char *tmp=NULL;
00915
00916 if (!change_password_realtime(vmu, newpassword))
00917 return;
00918
00919
00920 if ((cfg = ast_config_load_with_comments(VOICEMAIL_CONFIG))) {
00921 while ((category = ast_category_browse(cfg, category))) {
00922 if (!strcasecmp(category, vmu->context)) {
00923 tmp = ast_variable_retrieve(cfg, category, vmu->mailbox);
00924 if (!tmp) {
00925 ast_log(LOG_WARNING, "We could not find the mailbox.\n");
00926 break;
00927 }
00928 value = strstr(tmp,",");
00929 if (!value) {
00930 new = alloca(strlen(newpassword)+1);
00931 sprintf(new, "%s", newpassword);
00932 } else {
00933 new = alloca((strlen(value)+strlen(newpassword)+1));
00934 sprintf(new,"%s%s", newpassword, value);
00935 }
00936 if (!(cat = ast_category_get(cfg, category))) {
00937 ast_log(LOG_WARNING, "Failed to get category structure.\n");
00938 break;
00939 }
00940 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
00941 }
00942 }
00943
00944 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00945 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00946 config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
00947 }
00948 category = NULL;
00949 var = NULL;
00950
00951
00952 if ((cfg = ast_config_load_with_comments("users.conf"))) {
00953 if (option_debug > 3)
00954 ast_log(LOG_DEBUG, "we are looking for %s\n", vmu->mailbox);
00955 while ((category = ast_category_browse(cfg, category))) {
00956 if (option_debug > 3)
00957 ast_log(LOG_DEBUG, "users.conf: %s\n", category);
00958 if (!strcasecmp(category, vmu->mailbox)) {
00959 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
00960 if (option_debug > 3)
00961 ast_log(LOG_DEBUG, "looks like we need to make vmsecret!\n");
00962 var = ast_variable_new("vmsecret", newpassword);
00963 }
00964 new = alloca(strlen(newpassword)+1);
00965 sprintf(new, "%s", newpassword);
00966 if (!(cat = ast_category_get(cfg, category))) {
00967 if (option_debug > 3)
00968 ast_log(LOG_DEBUG, "failed to get category!\n");
00969 break;
00970 }
00971 if (!var)
00972 ast_variable_update(cat, "vmsecret", new, NULL, 0);
00973 else
00974 ast_variable_append(cat, var);
00975 }
00976 }
00977
00978 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00979 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00980 config_text_file_save("users.conf", cfg, "AppVoicemail");
00981 }
00982 }
00983
00984 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
00985 {
00986 char buf[255];
00987 snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
00988 if (!ast_safe_system(buf)) {
00989 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00990
00991 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00992 }
00993 }
00994
00995 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
00996 {
00997 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
00998 }
00999
01000 static int make_file(char *dest, const int len, const char *dir, const int num)
01001 {
01002 return snprintf(dest, len, "%s/msg%04d", dir, num);
01003 }
01004
01005
01006 static FILE *vm_mkftemp(char *template)
01007 {
01008 FILE *p = NULL;
01009 int pfd = mkstemp(template);
01010 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01011 if (pfd > -1) {
01012 p = fdopen(pfd, "w+");
01013 if (!p) {
01014 close(pfd);
01015 pfd = -1;
01016 }
01017 }
01018 return p;
01019 }
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01030 {
01031 mode_t mode = VOICEMAIL_DIR_MODE;
01032
01033 if (!ast_strlen_zero(context)) {
01034 make_dir(dest, len, context, "", "");
01035 if (mkdir(dest, mode) && errno != EEXIST) {
01036 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
01037 return -1;
01038 }
01039 }
01040 if (!ast_strlen_zero(ext)) {
01041 make_dir(dest, len, context, ext, "");
01042 if (mkdir(dest, mode) && errno != EEXIST) {
01043 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
01044 return -1;
01045 }
01046 }
01047 if (!ast_strlen_zero(folder)) {
01048 make_dir(dest, len, context, ext, folder);
01049 if (mkdir(dest, mode) && errno != EEXIST) {
01050 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
01051 return -1;
01052 }
01053 }
01054 return 0;
01055 }
01056
01057 static char *mbox(int id)
01058 {
01059 static char *msgs[] = {
01060 "INBOX",
01061 "Old",
01062 "Work",
01063 "Family",
01064 "Friends",
01065 "Cust1",
01066 "Cust2",
01067 "Cust3",
01068 "Cust4",
01069 "Cust5",
01070 };
01071 return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "tmp";
01072 }
01073
01074 static void free_user(struct ast_vm_user *vmu)
01075 {
01076 if (ast_test_flag(vmu, VM_ALLOCED))
01077 free(vmu);
01078 }
01079
01080 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01081
01082 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01083 if (!vms->dh_arraysize) {
01084
01085 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01086 return -1;
01087 }
01088 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01089 return -1;
01090 }
01091 vms->dh_arraysize = arraysize;
01092 } else if (vms->dh_arraysize < arraysize) {
01093 if (!(vms->deleted = ast_realloc(vms->deleted, arraysize * sizeof(int)))) {
01094 return -1;
01095 }
01096 if (!(vms->heard = ast_realloc(vms->heard, arraysize * sizeof(int)))) {
01097 return -1;
01098 }
01099 memset(vms->deleted, 0, arraysize * sizeof(int));
01100 memset(vms->heard, 0, arraysize * sizeof(int));
01101 vms->dh_arraysize = arraysize;
01102 }
01103
01104 return 0;
01105 }
01106
01107
01108
01109 #ifdef IMAP_STORAGE
01110 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01111 {
01112 char arg[10];
01113 struct vm_state *vms;
01114 unsigned long messageNum;
01115
01116
01117 if (msgnum < 0) {
01118 ast_filedelete(file, NULL);
01119 return;
01120 }
01121
01122 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01123 ast_log(LOG_WARNING, "Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->mailbox, msgnum);
01124 return;
01125 }
01126
01127
01128
01129 messageNum = vms->msgArray[msgnum];
01130 if (messageNum == 0) {
01131 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n",msgnum,messageNum);
01132 return;
01133 }
01134 if (option_debug > 2)
01135 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n",msgnum,messageNum);
01136
01137 snprintf (arg, sizeof(arg), "%lu",messageNum);
01138 ast_mutex_lock(&vms->lock);
01139 mail_setflag (vms->mailstream,arg,"\\DELETED");
01140 mail_expunge(vms->mailstream);
01141 ast_mutex_unlock(&vms->lock);
01142 }
01143
01144 static int imap_retrieve_file(const char *dir, const int msgnum, const struct ast_vm_user *vmu)
01145 {
01146 BODY *body;
01147 char *header_content;
01148 char *attachedfilefmt;
01149 const char *cid_num;
01150 const char *cid_name;
01151 const char *duration;
01152 const char *context;
01153 const char *category;
01154 const char *origtime;
01155 struct vm_state *vms;
01156 char text_file[PATH_MAX];
01157 FILE *text_file_ptr;
01158
01159
01160
01161
01162 if (msgnum < 0) {
01163 return 0;
01164 }
01165
01166
01167
01168
01169 if(!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01170
01171
01172
01173
01174
01175
01176
01177 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01178 return -1;
01179 }
01180
01181 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01182
01183
01184 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01185 return 0;
01186 }
01187
01188 if (option_debug > 2)
01189 ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01190 if (vms->msgArray[msgnum] == 0) {
01191 ast_log (LOG_WARNING,"Trying to access unknown message\n");
01192 return -1;
01193 }
01194
01195
01196 ast_mutex_lock(&vms->lock);
01197 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01198 ast_mutex_unlock(&vms->lock);
01199
01200 if (ast_strlen_zero(header_content)) {
01201 ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[msgnum]);
01202 return -1;
01203 }
01204
01205 ast_mutex_lock(&vms->lock);
01206 mail_fetchstructure (vms->mailstream,vms->msgArray[msgnum],&body);
01207 ast_mutex_unlock(&vms->lock);
01208
01209
01210 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01211 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01212 } else {
01213 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01214 return -1;
01215 }
01216
01217
01218
01219 strsep(&attachedfilefmt, ".");
01220 if (!attachedfilefmt) {
01221 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01222 return -1;
01223 }
01224
01225 save_body(body, vms, "2", attachedfilefmt);
01226
01227
01228 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01229
01230 if (!(text_file_ptr = fopen(text_file, "w"))) {
01231 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01232 }
01233
01234 fprintf(text_file_ptr, "%s\n", "[message]");
01235
01236 cid_name = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:");
01237 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(cid_name, ""));
01238 cid_num = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:");
01239 fprintf(text_file_ptr, "<%s>\n", S_OR(cid_num, ""));
01240 context = get_header_by_tag(header_content, "X-Asterisk-VM-Context:");
01241 fprintf(text_file_ptr, "context=%s\n", S_OR(context, ""));
01242 origtime = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:");
01243 fprintf(text_file_ptr, "origtime=%s\n", S_OR(origtime, ""));
01244 duration = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:");
01245 fprintf(text_file_ptr, "duration=%s\n", S_OR(origtime, ""));
01246 category = get_header_by_tag(header_content, "X-Asterisk-VM-Category:");
01247 fprintf(text_file_ptr, "category=%s\n", S_OR(category, ""));
01248
01249 fclose(text_file_ptr);
01250 return 0;
01251 }
01252
01253 static int folder_int(const char *folder)
01254 {
01255
01256 if (!folder)
01257 return 0;
01258 if (!strcasecmp(folder, "INBOX"))
01259 return 0;
01260 else if (!strcasecmp(folder, "Old"))
01261 return 1;
01262 else if (!strcasecmp(folder, "Work"))
01263 return 2;
01264 else if (!strcasecmp(folder, "Family"))
01265 return 3;
01266 else if (!strcasecmp(folder, "Friends"))
01267 return 4;
01268 else if (!strcasecmp(folder, "Cust1"))
01269 return 5;
01270 else if (!strcasecmp(folder, "Cust2"))
01271 return 6;
01272 else if (!strcasecmp(folder, "Cust3"))
01273 return 7;
01274 else if (!strcasecmp(folder, "Cust4"))
01275 return 8;
01276 else if (!strcasecmp(folder, "Cust5"))
01277 return 9;
01278 else
01279 return 0;
01280 }
01281
01282 static int messagecount(const char *context, const char *mailbox, const char *folder)
01283 {
01284 SEARCHPGM *pgm;
01285 SEARCHHEADER *hdr;
01286
01287 struct ast_vm_user *vmu, vmus;
01288 struct vm_state *vms_p;
01289 int ret = 0;
01290 int fold = folder_int(folder);
01291
01292 if (ast_strlen_zero(mailbox))
01293 return 0;
01294
01295
01296
01297 vmu = find_user(&vmus, context, mailbox);
01298 if (!vmu) {
01299 ast_log (LOG_ERROR,"Couldn't find mailbox %s in context %s\n",mailbox,context);
01300 return -1;
01301 } else {
01302
01303 if (vmu->imapuser[0] == '\0') {
01304 ast_log (LOG_WARNING,"IMAP user not set for mailbox %s\n",vmu->mailbox);
01305 return -1;
01306 }
01307 }
01308
01309
01310 vms_p = get_vm_state_by_imapuser(vmu->imapuser,1);
01311 if (!vms_p) {
01312 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
01313 }
01314 if (vms_p) {
01315 if (option_debug > 2)
01316 ast_log (LOG_DEBUG,"Returning before search - user is logged in\n");
01317 if (fold == 0) {
01318 return vms_p->newmessages;
01319 }
01320 if (fold == 1) {
01321 return vms_p->oldmessages;
01322 }
01323 }
01324
01325
01326 vms_p = get_vm_state_by_imapuser(vmu->imapuser,0);
01327 if (!vms_p) {
01328 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
01329 }
01330
01331 if (!vms_p) {
01332 if (!(vms_p = create_vm_state_from_user(vmu))) {
01333 ast_log(LOG_WARNING, "Unable to allocate space for new vm_state!\n");
01334 return -1;
01335 }
01336 }
01337 ret = init_mailstream(vms_p, fold);
01338 if (!vms_p->mailstream) {
01339 ast_log (LOG_ERROR,"IMAP mailstream is NULL\n");
01340 return -1;
01341 }
01342 if (ret == 0) {
01343 ast_mutex_lock(&vms_p->lock);
01344 pgm = mail_newsearchpgm ();
01345 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
01346 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
01347 pgm->header = hdr;
01348 if (fold != 1) {
01349 pgm->unseen = 1;
01350 pgm->seen = 0;
01351 }
01352
01353
01354
01355 else {
01356 pgm->unseen = 0;
01357 pgm->seen = 1;
01358 }
01359 pgm->undeleted = 1;
01360 pgm->deleted = 0;
01361
01362 vms_p->vmArrayIndex = 0;
01363 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
01364 if (fold == 0)
01365 vms_p->newmessages = vms_p->vmArrayIndex;
01366 if (fold == 1)
01367 vms_p->oldmessages = vms_p->vmArrayIndex;
01368
01369 mail_free_searchpgm(&pgm);
01370 ast_mutex_unlock(&vms_p->lock);
01371 vms_p->updated = 0;
01372 return vms_p->vmArrayIndex;
01373 } else {
01374 ast_mutex_lock(&vms_p->lock);
01375 mail_ping(vms_p->mailstream);
01376 ast_mutex_unlock(&vms_p->lock);
01377 }
01378 return 0;
01379 }
01380
01381 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
01382 {
01383
01384 check_quota(vms, imapfolder);
01385 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
01386 if (option_debug)
01387 ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
01388 ast_play_and_wait(chan, "vm-mailboxfull");
01389 return -1;
01390 }
01391
01392
01393 if (option_debug > 2)
01394 ast_log(LOG_DEBUG, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0));
01395 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
01396 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
01397 ast_play_and_wait(chan, "vm-mailboxfull");
01398 inprocess_count(vmu->mailbox, vmu->context, -1);
01399 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
01400 return -1;
01401 }
01402 return 0;
01403 }
01404
01405 static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms)
01406 {
01407 char *myserveremail = serveremail;
01408 char fn[PATH_MAX];
01409 char mailbox[256];
01410 char *stringp;
01411 FILE *p=NULL;
01412 char tmp[80] = "/tmp/astmail-XXXXXX";
01413 long len;
01414 void *buf;
01415 int tempcopy = 0;
01416 STRING str;
01417 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
01418
01419
01420 if (msgnum < 0)
01421 return 0;
01422
01423 if (imap_check_limits(chan, vms, vmu, msgcount)) {
01424 return -1;
01425 }
01426
01427
01428 fmt = ast_strdupa(fmt);
01429 stringp = fmt;
01430 strsep(&stringp, "|");
01431
01432 if (!ast_strlen_zero(vmu->serveremail))
01433 myserveremail = vmu->serveremail;
01434
01435 make_file(fn, sizeof(fn), dir, msgnum);
01436
01437 if (ast_strlen_zero(vmu->email)) {
01438
01439
01440
01441
01442 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
01443 tempcopy = 1;
01444 }
01445
01446 if (!strcmp(fmt, "wav49"))
01447 fmt = "WAV";
01448 if (option_debug > 2)
01449 ast_log(LOG_DEBUG, "Storing file '%s', format '%s'\n", fn, fmt);
01450
01451
01452 if ((p = vm_mkftemp(tmp)) == NULL) {
01453 ast_log(LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
01454 if (tempcopy)
01455 *(vmu->email) = '\0';
01456 return -1;
01457 } else {
01458 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, vms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, fmt, duration, 1, chan, NULL, 1);
01459
01460 len = ftell(p);
01461 rewind(p);
01462 if ((buf = ast_malloc(len+1)) == NIL) {
01463 ast_log(LOG_ERROR, "Can't allocate %ld bytes to read message\n", len+1);
01464 fclose(p);
01465 return -1;
01466 }
01467 if (fread(buf, len, 1, p) != 1) {
01468 ast_log(LOG_WARNING, "Short read: %s\n", strerror(errno));
01469 }
01470 ((char *)buf)[len] = '\0';
01471 INIT(&str, mail_string, buf, len);
01472 init_mailstream(vms, 0);
01473 imap_mailbox_name(mailbox, sizeof(mailbox), vms, 0, 1);
01474 ast_mutex_lock(&vms->lock);
01475 if (!mail_append(vms->mailstream, mailbox, &str))
01476 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
01477 ast_mutex_unlock(&vms->lock);
01478 fclose(p);
01479 unlink(tmp);
01480 ast_free(buf);
01481 if (option_debug > 2)
01482 ast_log(LOG_DEBUG, "%s stored\n", fn);
01483
01484
01485
01486 messagecount(vmu->context, vmu->mailbox, "INBOX");
01487 }
01488 if (tempcopy)
01489 *(vmu->email) = '\0';
01490 inprocess_count(vmu->mailbox, vmu->context, -1);
01491 return 0;
01492
01493 }
01494
01495 static int inboxcount(const char *mailbox_context, int *newmsgs, int *oldmsgs)
01496 {
01497 char tmp[PATH_MAX] = "";
01498 char *mailboxnc;
01499 char *context;
01500 char *mb;
01501 char *cur;
01502 if (newmsgs)
01503 *newmsgs = 0;
01504 if (oldmsgs)
01505 *oldmsgs = 0;
01506
01507 if (option_debug > 2)
01508 ast_log (LOG_DEBUG,"Mailbox is set to %s\n",mailbox_context);
01509
01510 if (ast_strlen_zero(mailbox_context))
01511 return 0;
01512
01513 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01514 context = strchr(tmp, '@');
01515 if (strchr(mailbox_context, ',')) {
01516 int tmpnew, tmpold;
01517 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01518 mb = tmp;
01519 while ((cur = strsep(&mb, ", "))) {
01520 if (!ast_strlen_zero(cur)) {
01521 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
01522 return -1;
01523 else {
01524 if (newmsgs)
01525 *newmsgs += tmpnew;
01526 if (oldmsgs)
01527 *oldmsgs += tmpold;
01528 }
01529 }
01530 }
01531 return 0;
01532 }
01533 if (context) {
01534 *context = '\0';
01535 mailboxnc = tmp;
01536 context++;
01537 } else {
01538 context = "default";
01539 mailboxnc = (char *)mailbox_context;
01540 }
01541 if (newmsgs) {
01542 if ((*newmsgs = messagecount(context, mailboxnc, "INBOX")) < 0)
01543 return -1;
01544 }
01545 if (oldmsgs) {
01546 if ((*oldmsgs = messagecount(context, mailboxnc, "Old")) < 0)
01547 return -1;
01548 }
01549 return 0;
01550 }
01551
01552
01553 static int has_voicemail(const char *mailbox, const char *folder)
01554 {
01555 char tmp[256], *tmp2, *mbox, *context;
01556 ast_copy_string(tmp, mailbox, sizeof(tmp));
01557 tmp2 = tmp;
01558 if (strchr(tmp2, ',')) {
01559 while ((mbox = strsep(&tmp2, ","))) {
01560 if (!ast_strlen_zero(mbox)) {
01561 if (has_voicemail(mbox, folder))
01562 return 1;
01563 }
01564 }
01565 }
01566 if ((context= strchr(tmp, '@')))
01567 *context++ = '\0';
01568 else
01569 context = "default";
01570 return messagecount(context, tmp, folder) ? 1 : 0;
01571 }
01572
01573 static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir)
01574 {
01575 struct vm_state *sendvms = NULL, *destvms = NULL;
01576 char messagestring[10];
01577 if (msgnum >= recip->maxmsg) {
01578 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
01579 return -1;
01580 }
01581 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
01582 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
01583 return -1;
01584 }
01585 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
01586 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
01587 return -1;
01588 }
01589 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
01590 ast_mutex_lock(&sendvms->lock);
01591 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(imbox)) == T)) {
01592 ast_mutex_unlock(&sendvms->lock);
01593 return 0;
01594 }
01595 ast_mutex_unlock(&sendvms->lock);
01596 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
01597 return -1;
01598 }
01599
01600 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
01601 {
01602 char tmp[256], *t = tmp;
01603 size_t left = sizeof(tmp);
01604
01605 if (box == 1) {
01606 ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox));
01607 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(1));
01608 } else {
01609 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
01610 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
01611 }
01612
01613
01614 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
01615
01616
01617 if (!ast_strlen_zero(authuser))
01618 ast_build_string(&t, &left, "/authuser=%s", authuser);
01619
01620
01621 if (!ast_strlen_zero(imapflags))
01622 ast_build_string(&t, &left, "/%s", imapflags);
01623
01624
01625 #if 1
01626 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
01627 #else
01628 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
01629 #endif
01630
01631 if (box == 0 || box == 1)
01632 snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX");
01633 else
01634 snprintf(spec, len, "%s%s%c%s", tmp, imapfolder, delimiter, mbox(box));
01635 }
01636
01637 static int init_mailstream(struct vm_state *vms, int box)
01638 {
01639 MAILSTREAM *stream = NIL;
01640 long debug;
01641 char tmp[256];
01642
01643 if (!vms) {
01644 ast_log (LOG_ERROR,"vm_state is NULL!\n");
01645 return -1;
01646 }
01647 if (option_debug > 2)
01648 ast_log (LOG_DEBUG,"vm_state user is:%s\n",vms->imapuser);
01649 if (vms->mailstream == NIL || !vms->mailstream) {
01650 if (option_debug)
01651 ast_log (LOG_DEBUG,"mailstream not set.\n");
01652 } else {
01653 stream = vms->mailstream;
01654 }
01655
01656 debug = NIL;
01657
01658 if (delimiter == '\0') {
01659 char *cp;
01660 #ifdef USE_SYSTEM_IMAP
01661 #include <imap/linkage.c>
01662 #elif defined(USE_SYSTEM_CCLIENT)
01663 #include <c-client/linkage.c>
01664 #else
01665 #include "linkage.c"
01666 #endif
01667
01668 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
01669 ast_mutex_lock(&vms->lock);
01670 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
01671 ast_mutex_unlock(&vms->lock);
01672 if (stream == NIL) {
01673 ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
01674 return -1;
01675 }
01676 get_mailbox_delimiter(stream);
01677
01678 for (cp = imapfolder; *cp; cp++)
01679 if (*cp == '/')
01680 *cp = delimiter;
01681 }
01682
01683 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
01684 if (option_debug > 2)
01685 ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box);
01686 ast_mutex_lock(&vms->lock);
01687 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
01688 ast_mutex_unlock(&vms->lock);
01689 if (vms->mailstream == NIL) {
01690 return -1;
01691 } else {
01692 return 0;
01693 }
01694 }
01695
01696 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
01697 {
01698 SEARCHPGM *pgm;
01699 SEARCHHEADER *hdr;
01700 int ret;
01701
01702 ast_copy_string(vms->imapuser,vmu->imapuser, sizeof(vms->imapuser));
01703 vms->imapversion = vmu->imapversion;
01704
01705 if (option_debug > 2)
01706 ast_log(LOG_DEBUG,"Before init_mailstream, user is %s\n",vmu->imapuser);
01707 ret = init_mailstream(vms, box);
01708 if (ret != 0 || !vms->mailstream) {
01709 ast_log (LOG_ERROR,"Could not initialize mailstream\n");
01710 return -1;
01711 }
01712
01713 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
01714
01715
01716 if (box == 0) {
01717 if (option_debug > 2)
01718 ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mbox(box));
01719 check_quota(vms,(char *)mbox(box));
01720 }
01721
01722 ast_mutex_lock(&vms->lock);
01723 pgm = mail_newsearchpgm();
01724
01725
01726 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
01727 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
01728 pgm->header = hdr;
01729 pgm->deleted = 0;
01730 pgm->undeleted = 1;
01731
01732
01733 if (box == 0) {
01734 pgm->unseen = 1;
01735 pgm->seen = 0;
01736 } else if (box == 1) {
01737 pgm->seen = 1;
01738 pgm->unseen = 0;
01739 }
01740
01741 vms->vmArrayIndex = 0;
01742 if (option_debug > 2)
01743 ast_log(LOG_DEBUG,"Before mail_search_full, user is %s\n",vmu->imapuser);
01744 mail_search_full (vms->mailstream, NULL, pgm, NIL);
01745
01746 vms->lastmsg = vms->vmArrayIndex - 1;
01747
01748
01749
01750
01751 if (box == 0 && !vms->dh_arraysize) {
01752 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
01753 }
01754 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
01755 ast_mutex_unlock(&vms->lock);
01756 return -1;
01757 }
01758
01759 mail_free_searchpgm(&pgm);
01760 ast_mutex_unlock(&vms->lock);
01761 return 0;
01762 }
01763
01764 static void write_file(char *filename, char *buffer, unsigned long len)
01765 {
01766 FILE *output;
01767
01768 output = fopen (filename, "w");
01769 if (fwrite (buffer, len, 1, output) != 1) {
01770 ast_log(LOG_WARNING, "Short write: %s\n", strerror(errno));
01771 }
01772 fclose (output);
01773 }
01774
01775 void mm_searched(MAILSTREAM *stream, unsigned long number)
01776 {
01777 struct vm_state *vms;
01778 char *mailbox;
01779 char *user;
01780 mailbox = stream->mailbox;
01781 user = get_user_by_mailbox(mailbox);
01782 vms = get_vm_state_by_imapuser(user,2);
01783 if (!vms) {
01784 vms = get_vm_state_by_imapuser(user, 0);
01785 }
01786 if (vms) {
01787 if (option_debug > 2)
01788 ast_log (LOG_DEBUG, "saving mailbox message number %lu as message %d. Interactive set to %d\n",number,vms->vmArrayIndex,vms->interactive);
01789 vms->msgArray[vms->vmArrayIndex++] = number;
01790 } else {
01791 ast_log (LOG_ERROR, "No state found.\n");
01792 }
01793 }
01794
01795 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
01796 {
01797 struct ast_variable *var;
01798 struct ast_vm_user *vmu;
01799
01800 vmu = ast_calloc(1, sizeof *vmu);
01801 if (!vmu)
01802 return NULL;
01803 ast_set_flag(vmu, VM_ALLOCED);
01804 populate_defaults(vmu);
01805
01806 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
01807 if (var) {
01808 apply_options_full(vmu, var);
01809 ast_variables_destroy(var);
01810 return vmu;
01811 } else {
01812 free(vmu);
01813 return NULL;
01814 }
01815 }
01816
01817
01818
01819 void mm_exists(MAILSTREAM * stream, unsigned long number)
01820 {
01821
01822 if (option_debug > 3)
01823 ast_log (LOG_DEBUG, "Entering EXISTS callback for message %ld\n", number);
01824 if (number == 0) return;
01825 set_update(stream);
01826 }
01827
01828
01829 void mm_expunged(MAILSTREAM * stream, unsigned long number)
01830 {
01831
01832 if (option_debug > 3)
01833 ast_log (LOG_DEBUG, "Entering EXPUNGE callback for message %ld\n", number);
01834 if (number == 0) return;
01835 set_update(stream);
01836 }
01837
01838
01839 void mm_flags(MAILSTREAM * stream, unsigned long number)
01840 {
01841
01842 if (option_debug > 3)
01843 ast_log (LOG_DEBUG, "Entering FLAGS callback for message %ld\n", number);
01844 if (number == 0) return;
01845 set_update(stream);
01846 }
01847
01848
01849 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
01850 {
01851 mm_log (string, errflg);
01852 }
01853
01854
01855 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
01856 {
01857 if (delimiter == '\0') {
01858 delimiter = delim;
01859 }
01860 if (option_debug > 4) {
01861 ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
01862 if (attributes & LATT_NOINFERIORS)
01863 ast_log(LOG_DEBUG, "no inferiors\n");
01864 if (attributes & LATT_NOSELECT)
01865 ast_log(LOG_DEBUG, "no select\n");
01866 if (attributes & LATT_MARKED)
01867 ast_log(LOG_DEBUG, "marked\n");
01868 if (attributes & LATT_UNMARKED)
01869 ast_log(LOG_DEBUG, "unmarked\n");
01870 }
01871 }
01872
01873
01874 void mm_lsub(MAILSTREAM * stream, int delimiter, char *mailbox, long attributes)
01875 {
01876 if (option_debug > 4) {
01877 ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delimiter, mailbox);
01878 if (attributes & LATT_NOINFERIORS)
01879 ast_log(LOG_DEBUG, "no inferiors\n");
01880 if (attributes & LATT_NOSELECT)
01881 ast_log(LOG_DEBUG, "no select\n");
01882 if (attributes & LATT_MARKED)
01883 ast_log(LOG_DEBUG, "marked\n");
01884 if (attributes & LATT_UNMARKED)
01885 ast_log(LOG_DEBUG, "unmarked\n");
01886 }
01887 }
01888
01889
01890 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
01891 {
01892 ast_log (LOG_NOTICE," Mailbox %s", mailbox);
01893 if (status->flags & SA_MESSAGES)
01894 ast_log (LOG_NOTICE,", %lu messages", status->messages);
01895 if (status->flags & SA_RECENT)
01896 ast_log (LOG_NOTICE,", %lu recent", status->recent);
01897 if (status->flags & SA_UNSEEN)
01898 ast_log (LOG_NOTICE,", %lu unseen", status->unseen);
01899 if (status->flags & SA_UIDVALIDITY)
01900 ast_log (LOG_NOTICE,", %lu UID validity", status->uidvalidity);
01901 if (status->flags & SA_UIDNEXT)
01902 ast_log (LOG_NOTICE,", %lu next UID", status->uidnext);
01903 ast_log (LOG_NOTICE,"\n");
01904 }
01905
01906
01907 void mm_log(char *string, long errflg)
01908 {
01909 switch ((short) errflg) {
01910 case NIL:
01911 if (option_debug)
01912 ast_log(LOG_DEBUG,"IMAP Info: %s\n", string);
01913 break;
01914 case PARSE:
01915 case WARN:
01916 ast_log (LOG_WARNING,"IMAP Warning: %s\n", string);
01917 break;
01918 case ERROR:
01919 ast_log (LOG_ERROR,"IMAP Error: %s\n", string);
01920 break;
01921 }
01922 }
01923
01924
01925 void mm_dlog(char *string)
01926 {
01927 ast_log (LOG_NOTICE, "%s\n", string);
01928 }
01929
01930
01931 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
01932 {
01933 struct ast_vm_user *vmu;
01934
01935 if (option_debug > 3)
01936 ast_log(LOG_DEBUG, "Entering callback mm_login\n");
01937
01938 ast_copy_string(user, mb->user, MAILTMPLEN);
01939
01940
01941 if (!ast_strlen_zero(authpassword)) {
01942 ast_copy_string(pwd, authpassword, MAILTMPLEN);
01943 } else {
01944 AST_LIST_TRAVERSE(&users, vmu, list) {
01945 if (!strcasecmp(mb->user, vmu->imapuser)) {
01946 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
01947 break;
01948 }
01949 }
01950 if (!vmu) {
01951 if ((vmu = find_user_realtime_imapuser(mb->user))) {
01952 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
01953 free_user(vmu);
01954 }
01955 }
01956 }
01957 }
01958
01959
01960 void mm_critical(MAILSTREAM * stream)
01961 {
01962 }
01963
01964
01965 void mm_nocritical(MAILSTREAM * stream)
01966 {
01967 }
01968
01969
01970 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
01971 {
01972 kill (getpid (), SIGSTOP);
01973 return NIL;
01974 }
01975
01976
01977 void mm_fatal(char *string)
01978 {
01979 ast_log(LOG_ERROR,"IMAP access FATAL error: %s\n", string);
01980 }
01981
01982
01983 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
01984 {
01985 struct vm_state *vms;
01986 char *mailbox;
01987 char *user;
01988 unsigned long usage = 0;
01989 unsigned long limit = 0;
01990
01991 while (pquota) {
01992 usage = pquota->usage;
01993 limit = pquota->limit;
01994 pquota = pquota->next;
01995 }
01996
01997 mailbox = stream->mailbox;
01998 user = get_user_by_mailbox(mailbox);
01999 vms = get_vm_state_by_imapuser(user,2);
02000 if (!vms) {
02001 vms = get_vm_state_by_imapuser(user, 0);
02002 }
02003 if (vms) {
02004 if (option_debug > 2)
02005 ast_log (LOG_DEBUG, "User %s usage is %lu, limit is %lu\n",user,usage,limit);
02006 vms->quota_usage = usage;
02007 vms->quota_limit = limit;
02008 } else {
02009 ast_log (LOG_ERROR, "No state found.\n");
02010 }
02011 }
02012
02013 static char *get_header_by_tag(char *header, char *tag)
02014 {
02015 char *start;
02016 int taglen;
02017 char *eol_pnt;
02018
02019 if (!header || !tag)
02020 return NULL;
02021
02022 taglen = strlen(tag) + 1;
02023 if (taglen < 1)
02024 return NULL;
02025
02026 start = strstr(header, tag);
02027 if (!start)
02028 return NULL;
02029
02030 ast_mutex_lock(&imaptemp_lock);
02031 ast_copy_string(imaptemp, start+taglen, sizeof(imaptemp));
02032 ast_mutex_unlock(&imaptemp_lock);
02033 if ((eol_pnt = strchr(imaptemp,'\r')) || (eol_pnt = strchr(imaptemp,'\n')))
02034 *eol_pnt = '\0';
02035 return imaptemp;
02036 }
02037
02038 static char *get_user_by_mailbox(char *mailbox)
02039 {
02040 char *start, *quote;
02041 char *eol_pnt;
02042
02043 if (!mailbox)
02044 return NULL;
02045
02046 start = strstr(mailbox,"/user=");
02047 if (!start)
02048 return NULL;
02049
02050 ast_mutex_lock(&imaptemp_lock);
02051 ast_copy_string(imaptemp, start+6, sizeof(imaptemp));
02052 ast_mutex_unlock(&imaptemp_lock);
02053
02054 quote = strchr(imaptemp,'\"');
02055 if (!quote) {
02056 eol_pnt = strchr(imaptemp,'/');
02057 if (!eol_pnt) {
02058 eol_pnt = strchr(imaptemp,'}');
02059 }
02060 *eol_pnt = '\0';
02061 return imaptemp;
02062 } else {
02063 eol_pnt = strchr(imaptemp+1,'\"');
02064 *eol_pnt = '\0';
02065 return imaptemp+1;
02066 }
02067 }
02068
02069 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02070 {
02071 struct vm_state *vms_p;
02072
02073 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02074 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02075 return vms_p;
02076 }
02077 if (option_debug > 4)
02078 ast_log(LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser);
02079 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02080 return NULL;
02081 ast_copy_string(vms_p->imapuser,vmu->imapuser, sizeof(vms_p->imapuser));
02082 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02083 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02084 vms_p->mailstream = NIL;
02085 vms_p->imapversion = vmu->imapversion;
02086 if (option_debug > 4)
02087 ast_log(LOG_DEBUG,"Copied %s to %s\n",vmu->imapuser,vms_p->imapuser);
02088 vms_p->updated = 1;
02089
02090 ast_copy_string(vms_p->curbox, mbox(0), sizeof(vms_p->curbox));
02091 init_vm_state(vms_p);
02092 vmstate_insert(vms_p);
02093 return vms_p;
02094 }
02095
02096 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive)
02097 {
02098 struct vmstate *vlist = NULL;
02099
02100 if (interactive) {
02101 struct vm_state *vms;
02102 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02103 vms = pthread_getspecific(ts_vmstate.key);
02104 return vms;
02105 }
02106
02107 ast_mutex_lock(&vmstate_lock);
02108 vlist = vmstates;
02109 while (vlist) {
02110 if (vlist->vms && vlist->vms->imapversion == imapversion) {
02111 if (vlist->vms->imapuser) {
02112 if (!strcmp(vlist->vms->imapuser,user)) {
02113 if (interactive == 2) {
02114 ast_mutex_unlock(&vmstate_lock);
02115 return vlist->vms;
02116 } else if (vlist->vms->interactive == interactive) {
02117 ast_mutex_unlock(&vmstate_lock);
02118 return vlist->vms;
02119 }
02120 }
02121 } else {
02122 if (option_debug > 2)
02123 ast_log(LOG_DEBUG, " error: imapuser is NULL for %s\n",user);
02124 }
02125 } else {
02126 if (option_debug > 2)
02127 ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",user);
02128 }
02129 vlist = vlist->next;
02130 }
02131 ast_mutex_unlock(&vmstate_lock);
02132 if (option_debug > 2)
02133 ast_log(LOG_DEBUG, "%s not found in vmstates\n",user);
02134 return NULL;
02135 }
02136
02137 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
02138 {
02139 struct vmstate *vlist = NULL;
02140 const char *local_context = S_OR(context, "default");
02141
02142 if (interactive) {
02143 struct vm_state *vms;
02144 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02145 vms = pthread_getspecific(ts_vmstate.key);
02146 return vms;
02147 }
02148
02149 ast_mutex_lock(&vmstate_lock);
02150 vlist = vmstates;
02151 if (option_debug > 2)
02152 ast_log(LOG_DEBUG, "Mailbox set to %s\n",mailbox);
02153 while (vlist) {
02154 if (vlist->vms) {
02155 if (vlist->vms->username && vlist->vms->context && vlist->vms->imapversion == imapversion) {
02156 if (option_debug > 2)
02157 ast_log(LOG_DEBUG, " comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n",mailbox,interactive,vlist->vms->username,vlist->vms->interactive);
02158 if (!strcmp(vlist->vms->username,mailbox) && !(strcmp(vlist->vms->context, local_context))) {
02159 if (option_debug > 2)
02160 ast_log(LOG_DEBUG, " Found it!\n");
02161 ast_mutex_unlock(&vmstate_lock);
02162 return vlist->vms;
02163 }
02164 } else {
02165 if (option_debug > 2)
02166 ast_log(LOG_DEBUG, " error: username or context is NULL for %s\n",mailbox);
02167 }
02168 } else {
02169 if (option_debug > 2)
02170 ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",mailbox);
02171 }
02172 vlist = vlist->next;
02173 }
02174 ast_mutex_unlock(&vmstate_lock);
02175 if (option_debug > 2)
02176 ast_log(LOG_DEBUG, "%s not found in vmstates\n",mailbox);
02177 return NULL;
02178 }
02179
02180 static void vmstate_insert(struct vm_state *vms)
02181 {
02182 struct vmstate *v;
02183 struct vm_state *altvms;
02184
02185
02186
02187
02188 if (vms->interactive == 1) {
02189 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
02190 if (altvms) {
02191 if (option_debug > 2)
02192 ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username);
02193 vms->newmessages = altvms->newmessages;
02194 vms->oldmessages = altvms->oldmessages;
02195
02196 copy_msgArray(vms, altvms);
02197 vms->vmArrayIndex = altvms->vmArrayIndex;
02198 vms->lastmsg = altvms->lastmsg;
02199 vms->curmsg = altvms->curmsg;
02200
02201 vms->persist_vms = altvms;
02202
02203 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
02204 vms->mailstream = altvms->mailstream;
02205 #else
02206 vms->mailstream = NIL;
02207 #endif
02208 }
02209 return;
02210 }
02211
02212 v = (struct vmstate *)malloc(sizeof(struct vmstate));
02213 if (!v) {
02214 ast_log(LOG_ERROR, "Out of memory\n");
02215 }
02216 if (option_debug > 2)
02217 ast_log(LOG_DEBUG, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02218 ast_mutex_lock(&vmstate_lock);
02219 v->vms = vms;
02220 v->next = vmstates;
02221 vmstates = v;
02222 ast_mutex_unlock(&vmstate_lock);
02223 }
02224
02225 static void vmstate_delete(struct vm_state *vms)
02226 {
02227 struct vmstate *vc, *vf = NULL, *vl = NULL;
02228 struct vm_state *altvms;
02229
02230
02231
02232 if (vms->interactive == 1) {
02233 altvms = vms->persist_vms;
02234 if (altvms) {
02235 if (option_debug > 2)
02236 ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username);
02237 altvms->newmessages = vms->newmessages;
02238 altvms->oldmessages = vms->oldmessages;
02239 altvms->updated = 1;
02240 }
02241 vms->mailstream = mail_close(vms->mailstream);
02242
02243
02244 return;
02245 }
02246
02247 ast_mutex_lock(&vmstate_lock);
02248 vc = vmstates;
02249 if (option_debug > 2)
02250 ast_log(LOG_DEBUG, "Removing vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02251 while (vc) {
02252 if (vc->vms == vms) {
02253 vf = vc;
02254 if (vl)
02255 vl->next = vc->next;
02256 else
02257 vmstates = vc->next;
02258 break;
02259 }
02260 vl = vc;
02261 vc = vc->next;
02262 }
02263 if (!vf) {
02264 ast_log(LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02265 } else {
02266 ast_mutex_destroy(&vf->vms->lock);
02267 free(vf);
02268 }
02269 ast_mutex_unlock(&vmstate_lock);
02270 }
02271
02272 static void set_update(MAILSTREAM * stream)
02273 {
02274 struct vm_state *vms;
02275 char *mailbox;
02276 char *user;
02277
02278 mailbox = stream->mailbox;
02279 user = get_user_by_mailbox(mailbox);
02280 vms = get_vm_state_by_imapuser(user, 0);
02281 if (vms) {
02282 if (option_debug > 2)
02283 ast_log (LOG_DEBUG, "User %s mailbox set for update.\n",user);
02284 vms->updated = 1;
02285 } else {
02286 if (option_debug > 2)
02287 ast_log (LOG_WARNING, "User %s mailbox not found for update.\n",user);
02288 }
02289 }
02290
02291 static void init_vm_state(struct vm_state *vms)
02292 {
02293 int x;
02294 vms->vmArrayIndex = 0;
02295 for (x = 0; x < 256; x++) {
02296 vms->msgArray[x] = 0;
02297 }
02298 ast_mutex_init(&vms->lock);
02299 }
02300
02301 static void copy_msgArray(struct vm_state *dst, struct vm_state *src)
02302 {
02303 int x;
02304 for (x = 0; x<256; x++) {
02305 dst->msgArray[x] = src->msgArray[x];
02306 }
02307 }
02308
02309 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format)
02310 {
02311 char *body_content;
02312 char *body_decoded;
02313 unsigned long len;
02314 unsigned long newlen;
02315 char filename[256];
02316
02317 if (!body || body == NIL)
02318 return -1;
02319 ast_mutex_lock(&vms->lock);
02320 body_content = mail_fetchbody (vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
02321 ast_mutex_unlock(&vms->lock);
02322 if (body_content != NIL) {
02323 snprintf(filename, sizeof(filename), "%s.%s", vms->fn, format);
02324
02325 body_decoded = rfc822_base64 ((unsigned char *)body_content, len, &newlen);
02326 write_file (filename, (char *) body_decoded, newlen);
02327 }
02328 return 0;
02329 }
02330
02331
02332
02333 static void get_mailbox_delimiter(MAILSTREAM *stream) {
02334 char tmp[50];
02335 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
02336 mail_list(stream, tmp, "*");
02337 }
02338
02339
02340 static void check_quota(struct vm_state *vms, char *mailbox) {
02341 ast_mutex_lock(&vms->lock);
02342 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
02343 if (option_debug > 2)
02344 ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mailbox);
02345 if (vms && vms->mailstream != NULL) {
02346 imap_getquotaroot(vms->mailstream, mailbox);
02347 } else {
02348 ast_log(LOG_WARNING,"Mailstream not available for mailbox: %s\n",mailbox);
02349 }
02350 ast_mutex_unlock(&vms->lock);
02351 }
02352 #endif
02353
02354
02355
02356
02357 static int vm_lock_path(const char *path)
02358 {
02359 switch (ast_lock_path(path)) {
02360 case AST_LOCK_TIMEOUT:
02361 return -1;
02362 default:
02363 return 0;
02364 }
02365 }
02366
02367
02368 #ifdef ODBC_STORAGE
02369 struct generic_prepare_struct {
02370 char *sql;
02371 int argc;
02372 char **argv;
02373 };
02374
02375 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
02376 {
02377 struct generic_prepare_struct *gps = data;
02378 int res, i;
02379 SQLHSTMT stmt;
02380
02381 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02382 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02383 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
02384 return NULL;
02385 }
02386 res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS);
02387 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02388 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
02389 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02390 return NULL;
02391 }
02392 for (i = 0; i < gps->argc; i++)
02393 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
02394
02395 return stmt;
02396 }
02397
02398 static int retrieve_file(char *dir, int msgnum)
02399 {
02400 int x = 0;
02401 int res;
02402 int fd=-1;
02403 size_t fdlen = 0;
02404 void *fdm = MAP_FAILED;
02405 SQLSMALLINT colcount=0;
02406 SQLHSTMT stmt;
02407 char sql[PATH_MAX];
02408 char fmt[80]="";
02409 char *c;
02410 char coltitle[256];
02411 SQLSMALLINT collen;
02412 SQLSMALLINT datatype;
02413 SQLSMALLINT decimaldigits;
02414 SQLSMALLINT nullable;
02415 SQLULEN colsize;
02416 SQLLEN colsize2;
02417 FILE *f=NULL;
02418 char rowdata[80];
02419 char fn[PATH_MAX];
02420 char full_fn[PATH_MAX];
02421 char msgnums[80];
02422 char *argv[] = { dir, msgnums };
02423 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02424
02425 struct odbc_obj *obj;
02426 obj = ast_odbc_request_obj(odbc_database, 0);
02427 if (obj) {
02428 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02429 c = strchr(fmt, '|');
02430 if (c)
02431 *c = '\0';
02432 if (!strcasecmp(fmt, "wav49"))
02433 strcpy(fmt, "WAV");
02434 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
02435 if (msgnum > -1)
02436 make_file(fn, sizeof(fn), dir, msgnum);
02437 else
02438 ast_copy_string(fn, dir, sizeof(fn));
02439 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02440
02441 if (!(f = fopen(full_fn, "w+"))) {
02442 ast_log(LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
02443 goto yuck;
02444 }
02445
02446 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02447 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02448 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02449 if (!stmt) {
02450 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02451 ast_odbc_release_obj(obj);
02452 goto yuck;
02453 }
02454 res = SQLFetch(stmt);
02455 if (res == SQL_NO_DATA) {
02456 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02457 ast_odbc_release_obj(obj);
02458 goto yuck;
02459 }
02460 else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02461 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02462 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02463 ast_odbc_release_obj(obj);
02464 goto yuck;
02465 }
02466 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, 0770);
02467 if (fd < 0) {
02468 ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
02469 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02470 ast_odbc_release_obj(obj);
02471 goto yuck;
02472 }
02473 res = SQLNumResultCols(stmt, &colcount);
02474 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02475 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
02476 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02477 ast_odbc_release_obj(obj);
02478 goto yuck;
02479 }
02480 if (f)
02481 fprintf(f, "[message]\n");
02482 for (x=0;x<colcount;x++) {
02483 rowdata[0] = '\0';
02484 colsize = 0;
02485 collen = sizeof(coltitle);
02486 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
02487 &datatype, &colsize, &decimaldigits, &nullable);
02488 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02489 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
02490 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02491 ast_odbc_release_obj(obj);
02492 goto yuck;
02493 }
02494 if (!strcasecmp(coltitle, "recording")) {
02495 off_t offset;
02496 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
02497 fdlen = colsize2;
02498 if (fd > -1) {
02499 char tmp[1]="";
02500 lseek(fd, fdlen - 1, SEEK_SET);
02501 if (write(fd, tmp, 1) != 1) {
02502 close(fd);
02503 fd = -1;
02504 continue;
02505 }
02506
02507 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
02508 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
02509 ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
02510 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02511 ast_odbc_release_obj(obj);
02512 goto yuck;
02513 } else {
02514 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
02515 munmap(fdm, CHUNKSIZE);
02516 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02517 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02518 unlink(full_fn);
02519 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02520 ast_odbc_release_obj(obj);
02521 goto yuck;
02522 }
02523 }
02524 }
02525 if (truncate(full_fn, fdlen) < 0) {
02526 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
02527 }
02528 }
02529 } else {
02530 SQLLEN ind;
02531 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &ind);
02532 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02533 SQLINTEGER nativeerror = 0;
02534 SQLSMALLINT diagbytes = 0;
02535 unsigned char state[10], diagnostic[256];
02536 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
02537 ast_log(LOG_WARNING, "SQL Get Data error: %s: %s!\n[%s]\n\n", state, diagnostic, sql);
02538 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02539 ast_odbc_release_obj(obj);
02540 goto yuck;
02541 }
02542 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
02543 fprintf(f, "%s=%s\n", coltitle, rowdata);
02544 }
02545 }
02546 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02547 ast_odbc_release_obj(obj);
02548 } else
02549 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02550 yuck:
02551 if (f)
02552 fclose(f);
02553 if (fd > -1)
02554 close(fd);
02555 return x - 1;
02556 }
02557
02558 static int last_message_index(struct ast_vm_user *vmu, char *dir)
02559 {
02560 int x = 0;
02561 int res;
02562 SQLHSTMT stmt;
02563 char sql[PATH_MAX];
02564 char rowdata[20];
02565 char *argv[] = { dir };
02566 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
02567
02568 struct odbc_obj *obj;
02569 obj = ast_odbc_request_obj(odbc_database, 0);
02570 if (obj) {
02571 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc limit 1", odbc_table);
02572
02573 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02574 if (!stmt) {
02575 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02576 ast_odbc_release_obj(obj);
02577 goto yuck;
02578 }
02579 res = SQLFetch(stmt);
02580 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02581 if (res == SQL_NO_DATA) {
02582 ast_log(LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
02583 } else {
02584 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02585 }
02586
02587 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02588 ast_odbc_release_obj(obj);
02589 goto yuck;
02590 }
02591 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02592 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02593 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02594 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02595 ast_odbc_release_obj(obj);
02596 goto yuck;
02597 }
02598 if (sscanf(rowdata, "%30d", &x) != 1)
02599 ast_log(LOG_WARNING, "Failed to read message index!\n");
02600 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02601 ast_odbc_release_obj(obj);
02602 return x;
02603 } else
02604 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02605 yuck:
02606 return x - 1;
02607 }
02608
02609 static int message_exists(char *dir, int msgnum)
02610 {
02611 int x = 0;
02612 int res;
02613 SQLHSTMT stmt;
02614 char sql[PATH_MAX];
02615 char rowdata[20];
02616 char msgnums[20];
02617 char *argv[] = { dir, msgnums };
02618 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02619
02620 struct odbc_obj *obj;
02621 obj = ast_odbc_request_obj(odbc_database, 0);
02622 if (obj) {
02623 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
02624 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02625 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02626 if (!stmt) {
02627 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02628 ast_odbc_release_obj(obj);
02629 goto yuck;
02630 }
02631 res = SQLFetch(stmt);
02632 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02633 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02634 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02635 ast_odbc_release_obj(obj);
02636 goto yuck;
02637 }
02638 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02639 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02640 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02641 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02642 ast_odbc_release_obj(obj);
02643 goto yuck;
02644 }
02645 if (sscanf(rowdata, "%30d", &x) != 1)
02646 ast_log(LOG_WARNING, "Failed to read message count!\n");
02647 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02648 ast_odbc_release_obj(obj);
02649 } else
02650 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02651 yuck:
02652 return x;
02653 }
02654
02655 static int count_messages(struct ast_vm_user *vmu, char *dir)
02656 {
02657 int x = 0;
02658 int res;
02659 SQLHSTMT stmt;
02660 char sql[PATH_MAX];
02661 char rowdata[20];
02662 char *argv[] = { dir };
02663 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
02664
02665 struct odbc_obj *obj;
02666 obj = ast_odbc_request_obj(odbc_database, 0);
02667 if (obj) {
02668 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
02669 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02670 if (!stmt) {
02671 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02672 ast_odbc_release_obj(obj);
02673 goto yuck;
02674 }
02675 res = SQLFetch(stmt);
02676 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02677 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02678 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02679 ast_odbc_release_obj(obj);
02680 goto yuck;
02681 }
02682 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02683 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02684 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02685 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02686 ast_odbc_release_obj(obj);
02687 goto yuck;
02688 }
02689 if (sscanf(rowdata, "%30d", &x) != 1)
02690 ast_log(LOG_WARNING, "Failed to read message count!\n");
02691 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02692 ast_odbc_release_obj(obj);
02693 return x;
02694 } else
02695 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02696 yuck:
02697 return x - 1;
02698
02699 }
02700
02701 static void delete_file(char *sdir, int smsg)
02702 {
02703 SQLHSTMT stmt;
02704 char sql[PATH_MAX];
02705 char msgnums[20];
02706 char *argv[] = { sdir, msgnums };
02707 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02708
02709 struct odbc_obj *obj;
02710 obj = ast_odbc_request_obj(odbc_database, 0);
02711 if (obj) {
02712 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02713 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02714 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02715 if (!stmt)
02716 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02717 else
02718 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02719 ast_odbc_release_obj(obj);
02720 } else
02721 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02722 return;
02723 }
02724
02725 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
02726 {
02727 SQLHSTMT stmt;
02728 char sql[512];
02729 char msgnums[20];
02730 char msgnumd[20];
02731 struct odbc_obj *obj;
02732 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
02733 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
02734
02735 delete_file(ddir, dmsg);
02736 obj = ast_odbc_request_obj(odbc_database, 0);
02737 if (obj) {
02738 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02739 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
02740 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,?,? FROM %s WHERE dir=? AND msgnum=?",odbc_table,odbc_table);
02741 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02742 if (!stmt)
02743 ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
02744 else
02745 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02746 ast_odbc_release_obj(obj);
02747 } else
02748 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02749 return;
02750 }
02751
02752 struct insert_cb_struct {
02753 char *dir;
02754 char *msgnum;
02755 void *recording;
02756 size_t recordinglen;
02757 SQLLEN indlen;
02758 const char *context;
02759 const char *macrocontext;
02760 const char *callerid;
02761 const char *origtime;
02762 const char *duration;
02763 char *mailboxuser;
02764 char *mailboxcontext;
02765 const char *category;
02766 char *sql;
02767 };
02768
02769 static SQLHSTMT insert_cb(struct odbc_obj *obj, void *vd)
02770 {
02771 struct insert_cb_struct *d = vd;
02772 int res;
02773 SQLHSTMT stmt;
02774
02775 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02776 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02777 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
02778 return NULL;
02779 }
02780
02781 res = SQLPrepare(stmt, (unsigned char *)d->sql, SQL_NTS);
02782 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02783 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", d->sql);
02784 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02785 return NULL;
02786 }
02787
02788 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->dir), 0, (void *)d->dir, 0, NULL);
02789 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->msgnum), 0, (void *)d->msgnum, 0, NULL);
02790 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, d->recordinglen, 0, (void *)d->recording, 0, &d->indlen);
02791 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->context), 0, (void *)d->context, 0, NULL);
02792 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->macrocontext), 0, (void *)d->macrocontext, 0, NULL);
02793 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->callerid), 0, (void *)d->callerid, 0, NULL);
02794 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->origtime), 0, (void *)d->origtime, 0, NULL);
02795 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->duration), 0, (void *)d->duration, 0, NULL);
02796 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxuser), 0, (void *)d->mailboxuser, 0, NULL);
02797 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxcontext), 0, (void *)d->mailboxcontext, 0, NULL);
02798 if (!ast_strlen_zero(d->category)) {
02799 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->category), 0, (void *)d->category, 0, NULL);
02800 }
02801
02802 return stmt;
02803 }
02804
02805 static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum)
02806 {
02807 int x = 0;
02808 int fd = -1;
02809 void *fdm = MAP_FAILED;
02810 size_t fdlen = -1;
02811 SQLHSTMT stmt;
02812 char sql[PATH_MAX];
02813 char msgnums[20];
02814 char fn[PATH_MAX];
02815 char full_fn[PATH_MAX];
02816 char fmt[80]="";
02817 char *c;
02818 struct insert_cb_struct d = {
02819 .dir = dir,
02820 .msgnum = msgnums,
02821 .context = "",
02822 .macrocontext = "",
02823 .callerid = "",
02824 .origtime = "",
02825 .duration = "",
02826 .mailboxuser = mailboxuser,
02827 .mailboxcontext = mailboxcontext,
02828 .category = "",
02829 .sql = sql
02830 };
02831 struct ast_config *cfg=NULL;
02832 struct odbc_obj *obj;
02833
02834 delete_file(dir, msgnum);
02835 obj = ast_odbc_request_obj(odbc_database, 0);
02836 if (obj) {
02837 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02838 c = strchr(fmt, '|');
02839 if (c)
02840 *c = '\0';
02841 if (!strcasecmp(fmt, "wav49"))
02842 strcpy(fmt, "WAV");
02843 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
02844 if (msgnum > -1)
02845 make_file(fn, sizeof(fn), dir, msgnum);
02846 else
02847 ast_copy_string(fn, dir, sizeof(fn));
02848 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02849 cfg = ast_config_load(full_fn);
02850 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02851 fd = open(full_fn, O_RDWR);
02852 if (fd < 0) {
02853 ast_log(LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
02854 ast_odbc_release_obj(obj);
02855 goto yuck;
02856 }
02857 if (cfg) {
02858 d.context = ast_variable_retrieve(cfg, "message", "context");
02859 if (!d.context) d.context = "";
02860 d.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext");
02861 if (!d.macrocontext) d.macrocontext = "";
02862 d.callerid = ast_variable_retrieve(cfg, "message", "callerid");
02863 if (!d.callerid) d.callerid = "";
02864 d.origtime = ast_variable_retrieve(cfg, "message", "origtime");
02865 if (!d.origtime) d.origtime = "";
02866 d.duration = ast_variable_retrieve(cfg, "message", "duration");
02867 if (!d.duration) d.duration = "";
02868 d.category = ast_variable_retrieve(cfg, "message", "category");
02869 if (!d.category) d.category = "";
02870 }
02871 fdlen = lseek(fd, 0, SEEK_END);
02872 lseek(fd, 0, SEEK_SET);
02873 printf("Length is %zd\n", fdlen);
02874 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
02875 if (fdm == MAP_FAILED) {
02876 ast_log(LOG_WARNING, "Memory map failed!\n");
02877 ast_odbc_release_obj(obj);
02878 goto yuck;
02879 }
02880 d.recording = fdm;
02881 d.recordinglen = d.indlen = fdlen;
02882 if (!ast_strlen_zero(d.category))
02883 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
02884 else
02885 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?, ? , ?,?,?,?,?,?,?)",odbc_table);
02886 stmt = ast_odbc_prepare_and_execute(obj, insert_cb, &d);
02887 if (stmt) {
02888 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02889 }
02890 ast_odbc_release_obj(obj);
02891 } else
02892 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02893 yuck:
02894 if (cfg)
02895 ast_config_destroy(cfg);
02896 if (fdm != MAP_FAILED)
02897 munmap(fdm, fdlen);
02898 if (fd > -1)
02899 close(fd);
02900 return x;
02901 }
02902
02903 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
02904 {
02905 SQLHSTMT stmt;
02906 char sql[PATH_MAX];
02907 char msgnums[20];
02908 char msgnumd[20];
02909 struct odbc_obj *obj;
02910 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
02911 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
02912
02913 delete_file(ddir, dmsg);
02914 obj = ast_odbc_request_obj(odbc_database, 0);
02915 if (obj) {
02916 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02917 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
02918 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table);
02919 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02920 if (!stmt)
02921 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02922 else
02923 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02924 ast_odbc_release_obj(obj);
02925 } else
02926 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02927 return;
02928 }
02929
02930 #else
02931 #ifndef IMAP_STORAGE
02932 static int count_messages(struct ast_vm_user *vmu, char *dir)
02933 {
02934
02935
02936 int vmcount = 0;
02937 DIR *vmdir = NULL;
02938 struct dirent *vment = NULL;
02939
02940 if (vm_lock_path(dir))
02941 return ERROR_LOCK_PATH;
02942
02943 if ((vmdir = opendir(dir))) {
02944 while ((vment = readdir(vmdir))) {
02945 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4))
02946 vmcount++;
02947 }
02948 closedir(vmdir);
02949 }
02950 ast_unlock_path(dir);
02951
02952 return vmcount;
02953 }
02954
02955 static void rename_file(char *sfn, char *dfn)
02956 {
02957 char stxt[PATH_MAX];
02958 char dtxt[PATH_MAX];
02959 ast_filerename(sfn,dfn,NULL);
02960 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
02961 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
02962 rename(stxt, dtxt);
02963 }
02964 #endif
02965
02966
02967
02968
02969
02970
02971
02972
02973
02974
02975
02976
02977 #if (!defined(IMAP_STORAGE) && !defined(ODBC_STORAGE))
02978 static int last_message_index(struct ast_vm_user *vmu, char *dir)
02979 {
02980 int x;
02981 unsigned char map[MAXMSGLIMIT] = "";
02982 DIR *msgdir;
02983 struct dirent *msgdirent;
02984 int msgdirint;
02985 char extension[4];
02986 int stopcount = 0;
02987
02988
02989
02990
02991
02992 if (!(msgdir = opendir(dir))) {
02993 return -1;
02994 }
02995
02996 while ((msgdirent = readdir(msgdir))) {
02997 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
02998 map[msgdirint] = 1;
02999 stopcount++;
03000 if (option_debug > 3) {
03001 ast_log(LOG_DEBUG, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
03002 }
03003 }
03004 }
03005 closedir(msgdir);
03006
03007 for (x = 0; x < vmu->maxmsg; x++) {
03008 if (map[x] == 1) {
03009 stopcount--;
03010 } else if (map[x] == 0 && !stopcount) {
03011 break;
03012 }
03013 }
03014
03015 return x - 1;
03016 }
03017 #endif
03018 #endif
03019 #if (defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
03020 static int remove_file(char *dir, int msgnum)
03021 {
03022 char fn[PATH_MAX];
03023 char full_fn[PATH_MAX];
03024 char msgnums[80];
03025
03026 if (msgnum > -1) {
03027 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03028 make_file(fn, sizeof(fn), dir, msgnum);
03029 } else {
03030 #ifndef IMAP_STORAGE
03031 ast_copy_string(fn, dir, sizeof(fn));
03032 #else
03033
03034
03035
03036 return 0;
03037 #endif
03038 }
03039 ast_filedelete(fn, NULL);
03040 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03041 unlink(full_fn);
03042 return 0;
03043 }
03044 #endif
03045
03046 #ifndef IMAP_STORAGE
03047 static int copy(char *infile, char *outfile)
03048 {
03049 int ifd;
03050 int ofd;
03051 int res;
03052 int len;
03053 char buf[4096];
03054
03055 #ifdef HARDLINK_WHEN_POSSIBLE
03056
03057 if (link(infile, outfile)) {
03058 #endif
03059 if ((ifd = open(infile, O_RDONLY)) < 0) {
03060 ast_log(LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
03061 return -1;
03062 }
03063 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
03064 ast_log(LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
03065 close(ifd);
03066 return -1;
03067 }
03068 do {
03069 len = read(ifd, buf, sizeof(buf));
03070 if (len < 0) {
03071 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
03072 close(ifd);
03073 close(ofd);
03074 unlink(outfile);
03075 }
03076 if (len) {
03077 res = write(ofd, buf, len);
03078 if (errno == ENOMEM || errno == ENOSPC || res != len) {
03079 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
03080 close(ifd);
03081 close(ofd);
03082 unlink(outfile);
03083 }
03084 }
03085 } while (len);
03086 close(ifd);
03087 close(ofd);
03088 return 0;
03089 #ifdef HARDLINK_WHEN_POSSIBLE
03090 } else {
03091
03092 return 0;
03093 }
03094 #endif
03095 }
03096 #endif
03097
03098 #ifndef IMAP_STORAGE
03099 static void copy_plain_file(char *frompath, char *topath)
03100 {
03101 char frompath2[PATH_MAX], topath2[PATH_MAX];
03102 ast_filecopy(frompath, topath, NULL);
03103 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
03104 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
03105 copy(frompath2, topath2);
03106 }
03107 #endif
03108
03109 #ifndef IMAP_STORAGE
03110 static int vm_delete(char *file)
03111 {
03112 char *txt;
03113 int txtsize = 0;
03114
03115 txtsize = (strlen(file) + 5)*sizeof(char);
03116 txt = alloca(txtsize);
03117
03118
03119
03120 snprintf(txt, txtsize, "%s.txt", file);
03121 unlink(txt);
03122 return ast_filedelete(file, NULL);
03123 }
03124 #endif
03125
03126 static int inbuf(struct baseio *bio, FILE *fi)
03127 {
03128 int l;
03129
03130 if (bio->ateof)
03131 return 0;
03132
03133 if ((l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
03134 if (ferror(fi))
03135 return -1;
03136
03137 bio->ateof = 1;
03138 return 0;
03139 }
03140
03141 bio->iolen= l;
03142 bio->iocp= 0;
03143
03144 return 1;
03145 }
03146
03147 static int inchar(struct baseio *bio, FILE *fi)
03148 {
03149 if (bio->iocp>=bio->iolen) {
03150 if (!inbuf(bio, fi))
03151 return EOF;
03152 }
03153
03154 return bio->iobuf[bio->iocp++];
03155 }
03156
03157 static int ochar(struct baseio *bio, int c, FILE *so)
03158 {
03159 if (bio->linelength >= BASELINELEN) {
03160 if (fputs(ENDL, so) == EOF) {
03161 return -1;
03162 }
03163
03164 bio->linelength = 0;
03165 }
03166
03167 if (putc(((unsigned char) c), so) == EOF) {
03168 return -1;
03169 }
03170
03171 bio->linelength++;
03172
03173 return 1;
03174 }
03175
03176 static int base_encode(char *filename, FILE *so)
03177 {
03178 unsigned char dtable[BASEMAXINLINE];
03179 int i,hiteof= 0;
03180 FILE *fi;
03181 struct baseio bio;
03182
03183 memset(&bio, 0, sizeof(bio));
03184 bio.iocp = BASEMAXINLINE;
03185
03186 if (!(fi = fopen(filename, "rb"))) {
03187 ast_log(LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
03188 return -1;
03189 }
03190
03191 for (i= 0;i<9;i++) {
03192 dtable[i]= 'A'+i;
03193 dtable[i+9]= 'J'+i;
03194 dtable[26+i]= 'a'+i;
03195 dtable[26+i+9]= 'j'+i;
03196 }
03197 for (i= 0;i<8;i++) {
03198 dtable[i+18]= 'S'+i;
03199 dtable[26+i+18]= 's'+i;
03200 }
03201 for (i= 0;i<10;i++) {
03202 dtable[52+i]= '0'+i;
03203 }
03204 dtable[62]= '+';
03205 dtable[63]= '/';
03206
03207 while (!hiteof){
03208 unsigned char igroup[3],ogroup[4];
03209 int c,n;
03210
03211 igroup[0]= igroup[1]= igroup[2]= 0;
03212
03213 for (n= 0;n<3;n++) {
03214 if ((c = inchar(&bio, fi)) == EOF) {
03215 hiteof= 1;
03216 break;
03217 }
03218
03219 igroup[n]= (unsigned char)c;
03220 }
03221
03222 if (n> 0) {
03223 ogroup[0]= dtable[igroup[0]>>2];
03224 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
03225 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
03226 ogroup[3]= dtable[igroup[2]&0x3F];
03227
03228 if (n<3) {
03229 ogroup[3]= '=';
03230
03231 if (n<2)
03232 ogroup[2]= '=';
03233 }
03234
03235 for (i= 0;i<4;i++)
03236 ochar(&bio, ogroup[i], so);
03237 }
03238 }
03239
03240 fclose(fi);
03241
03242 if (fputs(ENDL, so) == EOF) {
03243 return 0;
03244 }
03245
03246 return 1;
03247 }
03248
03249 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category)
03250 {
03251 char callerid[256];
03252 char fromdir[256], fromfile[256];
03253 struct ast_config *msg_cfg;
03254 const char *origcallerid, *origtime;
03255 char origcidname[80], origcidnum[80], origdate[80];
03256 int inttime;
03257
03258
03259 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
03260 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
03261 snprintf(passdata, passdatasize, "%d", msgnum);
03262 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
03263 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
03264 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
03265 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
03266 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
03267 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
03268 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
03269 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
03270 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
03271
03272
03273 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
03274 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
03275 if (strlen(fromfile) < sizeof(fromfile) - 5) {
03276 strcat(fromfile, ".txt");
03277 }
03278 if (!(msg_cfg = ast_config_load(fromfile))) {
03279 if (option_debug > 0) {
03280 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
03281 }
03282 return;
03283 }
03284
03285 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
03286 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
03287 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
03288 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
03289 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
03290 }
03291
03292 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
03293 time_t ttime = inttime;
03294 struct tm tm;
03295 ast_localtime(&ttime, &tm, NULL);
03296 strftime(origdate, sizeof(origdate), emaildateformat, &tm);
03297 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
03298 }
03299 ast_config_destroy(msg_cfg);
03300 }
03301
03302 static char *quote(const char *from, char *to, size_t len)
03303 {
03304 char *ptr = to;
03305 *ptr++ = '"';
03306 for (; ptr < to + len - 1; from++) {
03307 if (*from == '"')
03308 *ptr++ = '\\';
03309 else if (*from == '\0')
03310 break;
03311 *ptr++ = *from;
03312 }
03313 if (ptr < to + len - 1)
03314 *ptr++ = '"';
03315 *ptr = '\0';
03316 return to;
03317 }
03318
03319
03320
03321
03322 static const struct tm *vmu_tm(const struct ast_vm_user *vmu, struct tm *tm)
03323 {
03324 const struct vm_zone *z = NULL;
03325 time_t t = time(NULL);
03326
03327
03328 if (!ast_strlen_zero(vmu->zonetag)) {
03329
03330 AST_LIST_LOCK(&zones);
03331 AST_LIST_TRAVERSE(&zones, z, list) {
03332 if (!strcmp(z->name, vmu->zonetag))
03333 break;
03334 }
03335 AST_LIST_UNLOCK(&zones);
03336 }
03337 ast_localtime(&t, tm, z ? z->timezone : NULL);
03338 return tm;
03339 }
03340
03341
03342
03343
03344
03345 static int check_mime(const char *str)
03346 {
03347 for (; *str; str++) {
03348 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
03349 return 1;
03350 }
03351 }
03352 return 0;
03353 }
03354
03355
03356
03357
03358
03359
03360
03361
03362
03363
03364
03365
03366
03367
03368
03369
03370
03371 static char *encode_mime_str(const char *start, char *end, size_t endsize, size_t preamble, size_t postamble)
03372 {
03373 char tmp[80];
03374 int first_section = 1;
03375 size_t endlen = 0, tmplen = 0;
03376 *end = '\0';
03377
03378 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
03379 for (; *start; start++) {
03380 int need_encoding = 0;
03381 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
03382 need_encoding = 1;
03383 }
03384 if ((first_section && need_encoding && preamble + tmplen > 70) ||
03385 (first_section && !need_encoding && preamble + tmplen > 72) ||
03386 (!first_section && need_encoding && tmplen > 70) ||
03387 (!first_section && !need_encoding && tmplen > 72)) {
03388
03389 endlen += snprintf(end + endlen, endsize - endlen, "%s%s?=", first_section ? "" : " ", tmp);
03390 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
03391 first_section = 0;
03392 }
03393 if (need_encoding && *start == ' ') {
03394 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "_");
03395 } else if (need_encoding) {
03396 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "=%hhX", *start);
03397 } else {
03398 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%c", *start);
03399 }
03400 }
03401 snprintf(end + endlen, endsize - endlen, "%s%s?=%s", first_section ? "" : " ", tmp, endlen + postamble > 74 ? " " : "");
03402 return end;
03403 }
03404
03405 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap)
03406 {
03407 char date[256];
03408 char host[MAXHOSTNAMELEN] = "";
03409 char who[256];
03410 char bound[256];
03411 char fname[256];
03412 char dur[256];
03413 char enc_cidnum[256] = "", enc_cidname[256] = "";
03414 struct tm tm;
03415 char *passdata = NULL, *passdata2;
03416 size_t len_passdata = 0, len_passdata2, tmplen;
03417
03418
03419 len_passdata2 = strlen(vmu->fullname);
03420 if (emailsubject && (tmplen = strlen(emailsubject)) > len_passdata2) {
03421 len_passdata2 = tmplen;
03422 }
03423 if ((tmplen = strlen(emailtitle)) > len_passdata2) {
03424 len_passdata2 = tmplen;
03425 }
03426 if ((tmplen = strlen(fromstring)) > len_passdata2) {
03427 len_passdata2 = tmplen;
03428 }
03429 len_passdata2 = len_passdata2 * 3 + 200;
03430 passdata2 = alloca(len_passdata2);
03431
03432 if (cidnum) {
03433 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
03434 }
03435 if (cidname) {
03436 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
03437 }
03438 gethostname(host, sizeof(host) - 1);
03439 if (strchr(srcemail, '@'))
03440 ast_copy_string(who, srcemail, sizeof(who));
03441 else {
03442 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03443 }
03444 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03445 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03446 fprintf(p, "Date: %s" ENDL, date);
03447
03448
03449 strftime(date, sizeof(date), emaildateformat, &tm);
03450
03451 if (*fromstring) {
03452 struct ast_channel *ast;
03453 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03454 char *ptr;
03455 memset(passdata2, 0, len_passdata2);
03456 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category);
03457 pbx_substitute_variables_helper(ast, fromstring, passdata2, len_passdata2);
03458 len_passdata = strlen(passdata2) * 3 + 300;
03459 passdata = alloca(len_passdata);
03460 if (check_mime(passdata2)) {
03461 int first_line = 1;
03462 encode_mime_str(passdata2, passdata, len_passdata, strlen("From: "), strlen(who) + 3);
03463 while ((ptr = strchr(passdata, ' '))) {
03464 *ptr = '\0';
03465 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", passdata);
03466 first_line = 0;
03467 passdata = ptr + 1;
03468 }
03469 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", passdata, who);
03470 } else {
03471 fprintf(p, "From: %s <%s>" ENDL, quote(passdata2, passdata, len_passdata), who);
03472 }
03473 ast_channel_free(ast);
03474 } else
03475 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03476 } else
03477 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
03478
03479 if (check_mime(vmu->fullname)) {
03480 int first_line = 1;
03481 char *ptr;
03482 encode_mime_str(vmu->fullname, passdata2, len_passdata2, strlen("To: "), strlen(vmu->email) + 3);
03483 while ((ptr = strchr(passdata2, ' '))) {
03484 *ptr = '\0';
03485 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", passdata2);
03486 first_line = 0;
03487 passdata2 = ptr + 1;
03488 }
03489 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", passdata2, vmu->email);
03490 } else {
03491 fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata2), vmu->email);
03492 }
03493 if (emailsubject) {
03494 struct ast_channel *ast;
03495 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03496 int vmlen = strlen(emailsubject) * 3 + 200;
03497
03498 if (vmlen > len_passdata) {
03499 passdata = alloca(vmlen);
03500 len_passdata = vmlen;
03501 }
03502
03503 memset(passdata, 0, len_passdata);
03504 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, len_passdata, category);
03505 pbx_substitute_variables_helper(ast, emailsubject, passdata, len_passdata);
03506 if (check_mime(passdata)) {
03507 int first_line = 1;
03508 char *ptr;
03509 encode_mime_str(passdata, passdata2, len_passdata2, strlen("Subject: "), 0);
03510 while ((ptr = strchr(passdata2, ' '))) {
03511 *ptr = '\0';
03512 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
03513 first_line = 0;
03514 passdata2 = ptr + 1;
03515 }
03516 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
03517 } else {
03518 fprintf(p, "Subject: %s" ENDL, passdata);
03519 }
03520 ast_channel_free(ast);
03521 } else {
03522 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03523 }
03524 } else if (*emailtitle) {
03525 fprintf(p, emailtitle, msgnum + 1, mailbox) ;
03526 fprintf(p, ENDL) ;
03527 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
03528 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
03529 } else {
03530 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
03531 }
03532 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1, (unsigned int)ast_random(), mailbox, (int)getpid(), host);
03533 if (imap) {
03534
03535 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
03536
03537 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
03538 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
03539 #ifdef IMAP_STORAGE
03540 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
03541 #else
03542 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
03543 #endif
03544 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
03545 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
03546 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
03547 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
03548 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
03549 if (!ast_strlen_zero(category)) {
03550 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
03551 }
03552 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
03553 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long)time(NULL));
03554 }
03555 if (!ast_strlen_zero(cidnum)) {
03556 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
03557 }
03558 if (!ast_strlen_zero(cidname)) {
03559 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
03560 }
03561 fprintf(p, "MIME-Version: 1.0" ENDL);
03562 if (attach_user_voicemail) {
03563
03564 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox, (int)getpid(), (unsigned int)ast_random());
03565
03566 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
03567 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
03568 fprintf(p, "--%s" ENDL, bound);
03569 }
03570 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
03571 if (emailbody) {
03572 struct ast_channel *ast;
03573 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03574 char *passdata;
03575 int vmlen = strlen(emailbody)*3 + 200;
03576 if ((passdata = alloca(vmlen))) {
03577 memset(passdata, 0, vmlen);
03578 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03579 pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
03580 #ifdef IMAP_STORAGE
03581 {
03582
03583 char *line = passdata, *next;
03584 do {
03585
03586 if ((next = strchr(line, '\n'))) {
03587 *next++ = '\0';
03588 }
03589 fprintf(p, "%s" ENDL, line);
03590 line = next;
03591 } while (!ast_strlen_zero(line));
03592 }
03593 #else
03594 fprintf(p, "%s" ENDL, passdata);
03595 #endif
03596 } else
03597 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03598 ast_channel_free(ast);
03599 } else
03600 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03601 } else {
03602 if (strcmp(vmu->mailbox, mailbox)) {
03603
03604 struct ast_config *msg_cfg;
03605 const char *v;
03606 int inttime;
03607 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
03608
03609 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
03610 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
03611 if (strlen(fromfile) < sizeof(fromfile) - 5) {
03612 strcat(fromfile, ".txt");
03613 }
03614 if ((msg_cfg = ast_config_load(fromfile))) {
03615 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
03616 ast_copy_string(origcallerid, v, sizeof(origcallerid));
03617 }
03618
03619
03620
03621 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
03622 time_t ttime = inttime;
03623 struct tm tm;
03624 ast_localtime(&ttime, &tm, NULL);
03625 strftime(origdate, sizeof(origdate), emaildateformat, &tm);
03626 }
03627 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
03628 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
03629 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
03630 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
03631 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
03632 date, origcallerid, origdate);
03633 ast_config_destroy(msg_cfg);
03634 } else {
03635 goto plain_message;
03636 }
03637 } else {
03638 plain_message:
03639 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
03640 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
03641 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
03642 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
03643 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
03644 }
03645 }
03646 if (attach_user_voicemail) {
03647 char tmpdir[256], newtmp[256], tmpcmd[256], newfname[256];
03648 char newfmt[10];
03649 int tmpfd = -1;
03650 int exitstatus = 0;
03651
03652 if (!ast_strlen_zero(vmu->preprocesscmd) || !ast_strlen_zero(preprocesscmd)) {
03653 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
03654 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
03655 tmpfd = mkstemp(newtmp);
03656 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
03657 if (tmpfd > -1) {
03658 snprintf(newfmt, sizeof(newfmt), (!ast_strlen_zero(vmu->preprocesscmd)) ?
03659 ((!ast_strlen_zero(vmu->preprocessfmt)) ? vmu->preprocessfmt : format) :
03660 ((!ast_strlen_zero(preprocessfmt) ? preprocessfmt : format))
03661 );
03662 snprintf(newfname, sizeof(newfname), "%s.%s", newtmp, newfmt);
03663 snprintf(tmpcmd, sizeof(tmpcmd), "%s < %s.%s > %s", !ast_strlen_zero(vmu->preprocesscmd) ? vmu->preprocesscmd : preprocesscmd, attach, format, newfname);
03664 exitstatus = ast_safe_system(tmpcmd);
03665 if (option_debug)
03666 ast_log(LOG_DEBUG, "Executed preprocesscmd '%s', exitstatus %i\n", tmpcmd, exitstatus);
03667 if (exitstatus) {
03668 ast_log(LOG_WARNING, "Command %s exited with exitstatus %i\n", tmpcmd, exitstatus);
03669 close(tmpfd);
03670 unlink(fname);
03671 } else {
03672 attach = newtmp;
03673 strncpy(format, newfmt, 5);
03674 close(tmpfd);
03675 }
03676
03677 }
03678 }
03679
03680
03681 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
03682 int soxstatus = 0;
03683
03684 if (vmu->volgain < -.001 || vmu->volgain > .001) {
03685 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
03686 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
03687 tmpfd = mkstemp(newtmp);
03688 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
03689 if (option_debug > 2)
03690 ast_log(LOG_DEBUG, "newtmp: %s\n", newtmp);
03691 if (tmpfd > -1) {
03692 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
03693 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
03694 attach = newtmp;
03695 if (option_debug > 2) {
03696 ast_log(LOG_DEBUG, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
03697 }
03698 } else {
03699 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
03700 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
03701 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
03702 }
03703 }
03704 }
03705 fprintf(p, "--%s" ENDL, bound);
03706 if (strcasecmp(format, "mp3"))
03707 fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL, ctype, format, msgnum + 1, format);
03708 else
03709 fprintf(p, "Content-Type: audio/mpeg; name=\"msg%04d.%s\"" ENDL, msgnum + 1, format);
03710 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
03711 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
03712 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL, msgnum + 1, format);
03713 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
03714 base_encode(fname, p);
03715 fprintf(p, ENDL "--%s--" ENDL "." ENDL, bound);
03716 if (tmpfd > -1) {
03717 if (soxstatus == 0) {
03718 unlink(fname);
03719 }
03720 close(tmpfd);
03721 unlink(newtmp);
03722 }
03723 }
03724 }
03725
03726 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *fromfolder, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category)
03727 {
03728 FILE *p=NULL;
03729 char tmp[80] = "/tmp/astmail-XXXXXX";
03730 char tmp2[256];
03731 char *stringp;
03732
03733 if (vmu && ast_strlen_zero(vmu->email)) {
03734 ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
03735 return(0);
03736 }
03737
03738
03739 format = ast_strdupa(format);
03740 stringp = format;
03741 strsep(&stringp, "|");
03742
03743 if (!strcmp(format, "wav49"))
03744 format = "WAV";
03745 if (option_debug > 2)
03746 ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
03747
03748
03749 if ((p = vm_mkftemp(tmp)) == NULL) {
03750 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03751 return -1;
03752 } else {
03753 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, format, duration, attach_user_voicemail, chan, category, 0);
03754 fclose(p);
03755 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03756 ast_safe_system(tmp2);
03757 if (option_debug > 2)
03758 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
03759 }
03760 return 0;
03761 }
03762
03763 static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category)
03764 {
03765 char date[256];
03766 char host[MAXHOSTNAMELEN] = "";
03767 char who[256];
03768 char dur[PATH_MAX];
03769 char tmp[80] = "/tmp/astmail-XXXXXX";
03770 char tmp2[PATH_MAX];
03771 struct tm tm;
03772 FILE *p;
03773
03774 if ((p = vm_mkftemp(tmp)) == NULL) {
03775 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03776 return -1;
03777 } else {
03778 gethostname(host, sizeof(host)-1);
03779 if (strchr(srcemail, '@'))
03780 ast_copy_string(who, srcemail, sizeof(who));
03781 else {
03782 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03783 }
03784 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03785 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03786 fprintf(p, "Date: %s\n", date);
03787
03788 if (*pagerfromstring) {
03789 struct ast_channel *ast;
03790 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03791 char *passdata;
03792 int vmlen = strlen(fromstring)*3 + 200;
03793 if ((passdata = alloca(vmlen))) {
03794 memset(passdata, 0, vmlen);
03795 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03796 pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
03797 fprintf(p, "From: %s <%s>\n", passdata, who);
03798 } else
03799 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03800 ast_channel_free(ast);
03801 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03802 } else
03803 fprintf(p, "From: Asterisk PBX <%s>\n", who);
03804 fprintf(p, "To: %s\n", pager);
03805 if (pagersubject) {
03806 struct ast_channel *ast;
03807 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03808 char *passdata;
03809 int vmlen = strlen(pagersubject) * 3 + 200;
03810 if ((passdata = alloca(vmlen))) {
03811 memset(passdata, 0, vmlen);
03812 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03813 pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
03814 fprintf(p, "Subject: %s\n\n", passdata);
03815 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03816 ast_channel_free(ast);
03817 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03818 } else
03819 fprintf(p, "Subject: New VM\n\n");
03820 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
03821 if (pagerbody) {
03822 struct ast_channel *ast;
03823 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03824 char *passdata;
03825 int vmlen = strlen(pagerbody)*3 + 200;
03826 if ((passdata = alloca(vmlen))) {
03827 memset(passdata, 0, vmlen);
03828 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03829 pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
03830 fprintf(p, "%s\n", passdata);
03831 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03832 ast_channel_free(ast);
03833 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03834 } else {
03835 fprintf(p, "New %s long msg in box %s\n"
03836 "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
03837 }
03838 fclose(p);
03839 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03840 ast_safe_system(tmp2);
03841 if (option_debug > 2)
03842 ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd);
03843 }
03844 return 0;
03845 }
03846
03847 static int get_date(char *s, int len)
03848 {
03849 struct tm tm;
03850 time_t t;
03851
03852 time(&t);
03853
03854 ast_localtime(&t, &tm, NULL);
03855
03856 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
03857 }
03858
03859 static int play_greeting(struct ast_channel *chan, struct ast_vm_user *vmu, char *filename, char *ecodes)
03860 {
03861 int res = -2;
03862
03863 #ifdef ODBC_STORAGE
03864 int success =
03865 #endif
03866 RETRIEVE(filename, -1, vmu);
03867 if (ast_fileexists(filename, NULL, NULL) > 0) {
03868 res = ast_streamfile(chan, filename, chan->language);
03869 if (res > -1)
03870 res = ast_waitstream(chan, ecodes);
03871 #ifdef ODBC_STORAGE
03872 if (success == -1) {
03873
03874 if (option_debug)
03875 ast_log(LOG_DEBUG, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
03876 store_file(filename, vmu->mailbox, vmu->context, -1);
03877 }
03878 #endif
03879 }
03880 DISPOSE(filename, -1);
03881
03882 return res;
03883 }
03884
03885 static int invent_message(struct ast_channel *chan, struct ast_vm_user *vmu, char *ext, int busy, char *ecodes)
03886 {
03887 int res;
03888 char fn[PATH_MAX];
03889 char dest[PATH_MAX];
03890
03891 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, ext);
03892
03893 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "greet"))) {
03894 ast_log(LOG_WARNING, "Failed to make directory(%s)\n", fn);
03895 return -1;
03896 }
03897
03898 res = play_greeting(chan, vmu, fn, ecodes);
03899 if (res == -2) {
03900
03901 res = ast_stream_and_wait(chan, "vm-theperson", chan->language, ecodes);
03902 if (res)
03903 return res;
03904 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
03905 }
03906
03907 if (res)
03908 return res;
03909
03910 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", chan->language, ecodes);
03911 return res;
03912 }
03913
03914 static void free_zone(struct vm_zone *z)
03915 {
03916 free(z);
03917 }
03918
03919 #ifdef ODBC_STORAGE
03920
03921 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
03922 {
03923 int x = -1;
03924 int res;
03925 SQLHSTMT stmt;
03926 char sql[PATH_MAX];
03927 char rowdata[20];
03928 char tmp[PATH_MAX] = "";
03929 struct odbc_obj *obj;
03930 char *context;
03931 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
03932
03933 if (newmsgs)
03934 *newmsgs = 0;
03935 if (oldmsgs)
03936 *oldmsgs = 0;
03937
03938
03939 if (ast_strlen_zero(mailbox))
03940 return 0;
03941
03942 ast_copy_string(tmp, mailbox, sizeof(tmp));
03943
03944 context = strchr(tmp, '@');
03945 if (context) {
03946 *context = '\0';
03947 context++;
03948 } else
03949 context = "default";
03950
03951 obj = ast_odbc_request_obj(odbc_database, 0);
03952 if (obj) {
03953 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
03954 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03955 if (!stmt) {
03956 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03957 ast_odbc_release_obj(obj);
03958 goto yuck;
03959 }
03960 res = SQLFetch(stmt);
03961 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03962 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03963 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03964 ast_odbc_release_obj(obj);
03965 goto yuck;
03966 }
03967 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03968 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03969 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03970 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03971 ast_odbc_release_obj(obj);
03972 goto yuck;
03973 }
03974 *newmsgs = atoi(rowdata);
03975 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03976
03977 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
03978 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03979 if (!stmt) {
03980 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03981 ast_odbc_release_obj(obj);
03982 goto yuck;
03983 }
03984 res = SQLFetch(stmt);
03985 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03986 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03987 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03988 ast_odbc_release_obj(obj);
03989 goto yuck;
03990 }
03991 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03992 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03993 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03994 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03995 ast_odbc_release_obj(obj);
03996 goto yuck;
03997 }
03998 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03999 ast_odbc_release_obj(obj);
04000 *oldmsgs = atoi(rowdata);
04001 x = 0;
04002 } else
04003 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04004
04005 yuck:
04006 return x;
04007 }
04008
04009 static int messagecount(const char *context, const char *mailbox, const char *folder)
04010 {
04011 struct odbc_obj *obj = NULL;
04012 int nummsgs = 0;
04013 int res;
04014 SQLHSTMT stmt = NULL;
04015 char sql[PATH_MAX];
04016 char rowdata[20];
04017 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04018 if (!folder)
04019 folder = "INBOX";
04020
04021 if (ast_strlen_zero(mailbox))
04022 return 0;
04023
04024 obj = ast_odbc_request_obj(odbc_database, 0);
04025 if (obj) {
04026 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
04027 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04028 if (!stmt) {
04029 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04030 goto yuck;
04031 }
04032 res = SQLFetch(stmt);
04033 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04034 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04035 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04036 goto yuck;
04037 }
04038 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04039 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04040 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04041 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04042 goto yuck;
04043 }
04044 nummsgs = atoi(rowdata);
04045 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04046 } else
04047 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04048
04049 yuck:
04050 if (obj)
04051 ast_odbc_release_obj(obj);
04052 return nummsgs;
04053 }
04054
04055 static int has_voicemail(const char *mailbox, const char *folder)
04056 {
04057 char tmp[256], *tmp2 = tmp, *mbox, *context;
04058 ast_copy_string(tmp, mailbox, sizeof(tmp));
04059 while ((context = mbox = strsep(&tmp2, ","))) {
04060 strsep(&context, "@");
04061 if (ast_strlen_zero(context))
04062 context = "default";
04063 if (messagecount(context, mbox, folder))
04064 return 1;
04065 }
04066 return 0;
04067 }
04068 #endif
04069 #ifndef IMAP_STORAGE
04070
04071 static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir)
04072 {
04073 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
04074 const char *frombox = mbox(imbox);
04075 int recipmsgnum;
04076 int res = 0;
04077
04078 ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
04079
04080 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04081
04082 if (!dir)
04083 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
04084 else
04085 ast_copy_string(fromdir, dir, sizeof(fromdir));
04086
04087 make_file(frompath, sizeof(frompath), fromdir, msgnum);
04088
04089 if (vm_lock_path(todir))
04090 return ERROR_LOCK_PATH;
04091
04092 recipmsgnum = 0;
04093 do {
04094 make_file(topath, sizeof(topath), todir, recipmsgnum);
04095 if (!EXISTS(todir, recipmsgnum, topath, chan->language))
04096 break;
04097 recipmsgnum++;
04098 } while (recipmsgnum < recip->maxmsg);
04099 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
04100 #ifndef ODBC_STORAGE
04101 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
04102 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
04103 } else {
04104 #endif
04105
04106
04107
04108 copy_plain_file(frompath, topath);
04109 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL);
04110 vm_delete(topath);
04111 #ifndef ODBC_STORAGE
04112 }
04113 #endif
04114 } else {
04115 ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
04116 res = -1;
04117 }
04118 ast_unlock_path(todir);
04119 notify_new_message(chan, recip, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
04120
04121 return res;
04122 }
04123 #endif
04124 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
04125 static int messagecount(const char *context, const char *mailbox, const char *folder)
04126 {
04127 return __has_voicemail(context, mailbox, folder, 0);
04128 }
04129
04130
04131 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
04132 {
04133 DIR *dir;
04134 struct dirent *de;
04135 char fn[256];
04136 int ret = 0;
04137 if (!folder)
04138 folder = "INBOX";
04139
04140 if (ast_strlen_zero(mailbox))
04141 return 0;
04142 if (!context)
04143 context = "default";
04144 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
04145 dir = opendir(fn);
04146 if (!dir)
04147 return 0;
04148 while ((de = readdir(dir))) {
04149 if (!strncasecmp(de->d_name, "msg", 3)) {
04150 if (shortcircuit) {
04151 ret = 1;
04152 break;
04153 } else if (!strncasecmp(de->d_name + 8, "txt", 3))
04154 ret++;
04155 }
04156 }
04157 closedir(dir);
04158 return ret;
04159 }
04160
04161
04162 static int has_voicemail(const char *mailbox, const char *folder)
04163 {
04164 char tmp[256], *tmp2 = tmp, *mbox, *context;
04165 ast_copy_string(tmp, mailbox, sizeof(tmp));
04166 while ((mbox = strsep(&tmp2, ","))) {
04167 if ((context = strchr(mbox, '@')))
04168 *context++ = '\0';
04169 else
04170 context = "default";
04171 if (__has_voicemail(context, mbox, folder, 1))
04172 return 1;
04173 }
04174 return 0;
04175 }
04176
04177
04178 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
04179 {
04180 char tmp[256];
04181 char *context;
04182
04183 if (newmsgs)
04184 *newmsgs = 0;
04185 if (oldmsgs)
04186 *oldmsgs = 0;
04187
04188 if (ast_strlen_zero(mailbox))
04189 return 0;
04190 if (strchr(mailbox, ',')) {
04191 int tmpnew, tmpold;
04192 char *mb, *cur;
04193
04194 ast_copy_string(tmp, mailbox, sizeof(tmp));
04195 mb = tmp;
04196 while ((cur = strsep(&mb, ", "))) {
04197 if (!ast_strlen_zero(cur)) {
04198 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
04199 return -1;
04200 else {
04201 if (newmsgs)
04202 *newmsgs += tmpnew;
04203 if (oldmsgs)
04204 *oldmsgs += tmpold;
04205 }
04206 }
04207 }
04208 return 0;
04209 }
04210 ast_copy_string(tmp, mailbox, sizeof(tmp));
04211 context = strchr(tmp, '@');
04212 if (context) {
04213 *context = '\0';
04214 context++;
04215 } else
04216 context = "default";
04217 if (newmsgs)
04218 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
04219 if (oldmsgs)
04220 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
04221 return 0;
04222 }
04223
04224 #endif
04225
04226 static void run_externnotify(char *context, char *extension)
04227 {
04228 char arguments[255];
04229 char ext_context[256] = "";
04230 int newvoicemails = 0, oldvoicemails = 0;
04231 struct ast_smdi_mwi_message *mwi_msg;
04232
04233 if (!ast_strlen_zero(context))
04234 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
04235 else
04236 ast_copy_string(ext_context, extension, sizeof(ext_context));
04237
04238 if (!strcasecmp(externnotify, "smdi")) {
04239 if (ast_app_has_voicemail(ext_context, NULL))
04240 ast_smdi_mwi_set(smdi_iface, extension);
04241 else
04242 ast_smdi_mwi_unset(smdi_iface, extension);
04243
04244 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
04245 ast_log(LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
04246 if (!strncmp(mwi_msg->cause, "INV", 3))
04247 ast_log(LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
04248 else if (!strncmp(mwi_msg->cause, "BLK", 3))
04249 ast_log(LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
04250 ast_log(LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
04251 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
04252 } else {
04253 if (option_debug)
04254 ast_log(LOG_DEBUG, "Successfully executed SMDI MWI change for %s\n", extension);
04255 }
04256 } else if (!ast_strlen_zero(externnotify)) {
04257 if (inboxcount(ext_context, &newvoicemails, &oldvoicemails)) {
04258 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
04259 } else {
04260 snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
04261 if (option_debug)
04262 ast_log(LOG_DEBUG, "Executing %s\n", arguments);
04263 ast_safe_system(arguments);
04264 }
04265 }
04266 }
04267
04268 struct leave_vm_options {
04269 unsigned int flags;
04270 signed char record_gain;
04271 };
04272
04273 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
04274 {
04275 #ifdef IMAP_STORAGE
04276 int newmsgs, oldmsgs;
04277 #endif
04278 struct vm_state *vms = NULL;
04279 char txtfile[PATH_MAX], tmptxtfile[PATH_MAX];
04280 char callerid[256];
04281 FILE *txt;
04282 char date[50];
04283 int txtdes;
04284 int res = 0;
04285 int msgnum;
04286 int duration = 0;
04287 int ausemacro = 0;
04288 int ousemacro = 0;
04289 int ouseexten = 0;
04290 char dir[PATH_MAX], tmpdir[PATH_MAX];
04291 char dest[PATH_MAX];
04292 char fn[PATH_MAX];
04293 char prefile[PATH_MAX] = "";
04294 char tempfile[PATH_MAX] = "";
04295 char ext_context[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2] = "";
04296 char fmt[80];
04297 char *context;
04298 char ecodes[16] = "#";
04299 char tmp[1324] = "", *tmpptr;
04300 struct ast_vm_user *vmu;
04301 struct ast_vm_user svm;
04302 const char *category = NULL;
04303
04304 if (strlen(ext) > sizeof(tmp) - 1) {
04305 ast_log(LOG_WARNING, "List of extensions is too long (>%ld). Truncating.\n", (long) sizeof(tmp) - 1);
04306 }
04307 ast_copy_string(tmp, ext, sizeof(tmp));
04308 ext = tmp;
04309 context = strchr(tmp, '@');
04310 if (context) {
04311 *context++ = '\0';
04312 tmpptr = strchr(context, '&');
04313 } else {
04314 tmpptr = strchr(ext, '&');
04315 }
04316
04317 if (tmpptr)
04318 *tmpptr++ = '\0';
04319
04320 category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
04321
04322 if (option_debug > 2)
04323 ast_log(LOG_DEBUG, "Before find_user\n");
04324 if (!(vmu = find_user(&svm, context, ext))) {
04325 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
04326 if (ast_test_flag(options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
04327 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
04328 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04329 return res;
04330 }
04331
04332 if (strcmp(vmu->context, "default"))
04333 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
04334 else
04335 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
04336 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
04337 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "busy");
04338 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
04339 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
04340 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "unavail");
04341 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
04342 }
04343 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
04344 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "temp"))) {
04345 ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
04346 return -1;
04347 }
04348 RETRIEVE(tempfile, -1, vmu);
04349 if (ast_fileexists(tempfile, NULL, NULL) > 0)
04350 ast_copy_string(prefile, tempfile, sizeof(prefile));
04351 DISPOSE(tempfile, -1);
04352
04353 #ifndef IMAP_STORAGE
04354 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
04355 #else
04356 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
04357 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
04358 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
04359 }
04360 #endif
04361 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp");
04362
04363
04364 if (ast_test_flag(vmu, VM_OPERATOR)) {
04365 if (!ast_strlen_zero(vmu->exit)) {
04366 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
04367 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04368 ouseexten = 1;
04369 }
04370 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
04371 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04372 ouseexten = 1;
04373 }
04374 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
04375 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04376 ousemacro = 1;
04377 }
04378 }
04379
04380 if (!ast_strlen_zero(vmu->exit)) {
04381 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
04382 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04383 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
04384 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04385 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
04386 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04387 ausemacro = 1;
04388 }
04389
04390
04391 if (!ast_strlen_zero(prefile)) {
04392 res = play_greeting(chan, vmu, prefile, ecodes);
04393 if (res == -2) {
04394
04395 if (option_debug)
04396 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
04397 res = invent_message(chan, vmu, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
04398 }
04399 if (res < 0) {
04400 if (option_debug)
04401 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
04402 free_user(vmu);
04403 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04404 return -1;
04405 }
04406 }
04407 if (res == '#') {
04408
04409 ast_set_flag(options, OPT_SILENT);
04410 res = 0;
04411 }
04412 if (!res && !ast_test_flag(options, OPT_SILENT)) {
04413 res = ast_stream_and_wait(chan, INTRO, chan->language, ecodes);
04414 if (res == '#') {
04415 ast_set_flag(options, OPT_SILENT);
04416 res = 0;
04417 }
04418 }
04419 if (res > 0)
04420 ast_stopstream(chan);
04421
04422
04423 if (res == '*') {
04424 chan->exten[0] = 'a';
04425 chan->exten[1] = '\0';
04426 if (!ast_strlen_zero(vmu->exit)) {
04427 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
04428 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
04429 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
04430 }
04431 chan->priority = 0;
04432 free_user(vmu);
04433 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
04434 return 0;
04435 }
04436
04437
04438 if (res == '0') {
04439 transfer:
04440 if (ouseexten || ousemacro) {
04441 chan->exten[0] = 'o';
04442 chan->exten[1] = '\0';
04443 if (!ast_strlen_zero(vmu->exit)) {
04444 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
04445 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
04446 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
04447 }
04448 ast_play_and_wait(chan, "transfer");
04449 chan->priority = 0;
04450 free_user(vmu);
04451 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
04452 }
04453 return OPERATOR_EXIT;
04454 }
04455 if (res < 0) {
04456 free_user(vmu);
04457 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04458 return -1;
04459 }
04460
04461 ast_copy_string(fmt, vmfmts, sizeof(fmt));
04462 if (!ast_strlen_zero(fmt)) {
04463 msgnum = 0;
04464
04465 #ifdef IMAP_STORAGE
04466
04467
04468 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
04469 if (res < 0) {
04470 ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
04471 return -1;
04472 }
04473 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
04474
04475
04476 if (!(vms = create_vm_state_from_user(vmu))) {
04477 ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
04478 return -1;
04479 }
04480 }
04481 vms->newmessages++;
04482
04483 msgnum = newmsgs + oldmsgs;
04484 if (option_debug > 2)
04485 ast_log(LOG_DEBUG, "Messagecount set to %d\n",msgnum);
04486 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
04487
04488 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
04489
04490 if (imap_check_limits(chan, vms, vmu, msgnum)) {
04491 goto leave_vm_out;
04492 }
04493 #else
04494 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
04495 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
04496 if (!res)
04497 res = ast_waitstream(chan, "");
04498 ast_log(LOG_WARNING, "No more messages possible\n");
04499 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04500 inprocess_count(vmu->mailbox, vmu->context, -1);
04501 goto leave_vm_out;
04502 }
04503
04504 #endif
04505 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
04506 txtdes = mkstemp(tmptxtfile);
04507 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
04508 if (txtdes < 0) {
04509 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
04510 if (!res)
04511 res = ast_waitstream(chan, "");
04512 ast_log(LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
04513 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04514 inprocess_count(vmu->mailbox, vmu->context, -1);
04515 goto leave_vm_out;
04516 }
04517
04518
04519 if (res >= 0) {
04520
04521 res = ast_stream_and_wait(chan, "beep", chan->language, "");
04522 }
04523
04524
04525 txt = fdopen(txtdes, "w+");
04526 if (txt) {
04527 get_date(date, sizeof(date));
04528 fprintf(txt,
04529 ";\n"
04530 "; Message Information file\n"
04531 ";\n"
04532 "[message]\n"
04533 "origmailbox=%s\n"
04534 "context=%s\n"
04535 "macrocontext=%s\n"
04536 "exten=%s\n"
04537 "priority=%d\n"
04538 "callerchan=%s\n"
04539 "callerid=%s\n"
04540 "origdate=%s\n"
04541 "origtime=%ld\n"
04542 "category=%s\n",
04543 ext,
04544 chan->context,
04545 chan->macrocontext,
04546 chan->exten,
04547 chan->priority,
04548 chan->name,
04549 ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"),
04550 date, (long)time(NULL),
04551 category ? category : "");
04552 } else
04553 ast_log(LOG_WARNING, "Error opening text file for output\n");
04554 res = play_record_review(chan, NULL, tmptxtfile, vmmaxmessage, fmt, 1, vmu, &duration, NULL, options->record_gain, vms);
04555
04556 if (txt) {
04557 if (duration < vmminmessage) {
04558 fclose(txt);
04559 if (option_verbose > 2)
04560 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
04561 ast_filedelete(tmptxtfile, NULL);
04562 unlink(tmptxtfile);
04563 inprocess_count(vmu->mailbox, vmu->context, -1);
04564 } else {
04565 fprintf(txt, "duration=%d\n", duration);
04566 fclose(txt);
04567 if (vm_lock_path(dir)) {
04568 ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
04569
04570 ast_filedelete(tmptxtfile, NULL);
04571 unlink(tmptxtfile);
04572 inprocess_count(vmu->mailbox, vmu->context, -1);
04573 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
04574 if (option_debug)
04575 ast_log(LOG_DEBUG, "The recorded media file is gone, so we should remove the .txt file too!\n");
04576 unlink(tmptxtfile);
04577 ast_unlock_path(dir);
04578 inprocess_count(vmu->mailbox, vmu->context, -1);
04579 } else {
04580 #ifndef IMAP_STORAGE
04581 msgnum = last_message_index(vmu, dir) + 1;
04582 #endif
04583 make_file(fn, sizeof(fn), dir, msgnum);
04584
04585
04586 #ifndef IMAP_STORAGE
04587 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
04588 #else
04589 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
04590 #endif
04591
04592 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
04593 ast_filerename(tmptxtfile, fn, NULL);
04594 rename(tmptxtfile, txtfile);
04595 inprocess_count(vmu->mailbox, vmu->context, -1);
04596
04597 ast_unlock_path(dir);
04598
04599
04600
04601 if (ast_fileexists(fn, NULL, NULL) > 0) {
04602 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms);
04603 }
04604
04605
04606 while (tmpptr) {
04607 struct ast_vm_user recipu, *recip;
04608 char *exten, *context;
04609
04610 exten = strsep(&tmpptr, "&");
04611 context = strchr(exten, '@');
04612 if (context) {
04613 *context = '\0';
04614 context++;
04615 }
04616 if ((recip = find_user(&recipu, context, exten))) {
04617 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir);
04618 free_user(recip);
04619 }
04620 }
04621
04622 if (ast_fileexists(fn, NULL, NULL)) {
04623 notify_new_message(chan, vmu, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
04624 DISPOSE(dir, msgnum);
04625 }
04626 }
04627 }
04628 } else {
04629 inprocess_count(vmu->mailbox, vmu->context, -1);
04630 }
04631 if (res == '0') {
04632 goto transfer;
04633 } else if (res > 0 && res != 't')
04634 res = 0;
04635
04636 if (duration < vmminmessage)
04637
04638 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04639 else
04640 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
04641 } else
04642 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
04643 leave_vm_out:
04644 free_user(vmu);
04645
04646 return res;
04647 }
04648
04649 #if !defined(IMAP_STORAGE)
04650 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
04651 {
04652
04653
04654 int x,dest;
04655 char sfn[PATH_MAX];
04656 char dfn[PATH_MAX];
04657
04658 if (vm_lock_path(dir))
04659 return ERROR_LOCK_PATH;
04660
04661 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
04662 make_file(sfn, sizeof(sfn), dir, x);
04663 if (EXISTS(dir, x, sfn, NULL)) {
04664
04665 if (x != dest) {
04666 make_file(dfn, sizeof(dfn), dir, dest);
04667 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
04668 }
04669
04670 dest++;
04671 }
04672 }
04673 ast_unlock_path(dir);
04674
04675 return dest;
04676 }
04677 #endif
04678
04679 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
04680 {
04681 int d;
04682 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, (char *) NULL);
04683 return d;
04684 }
04685
04686 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
04687 {
04688 #ifdef IMAP_STORAGE
04689
04690
04691 char sequence[10];
04692
04693 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
04694 if (option_debug > 2)
04695 ast_log(LOG_DEBUG, "Copying sequence %s to mailbox %s\n",sequence,(char *) mbox(box));
04696 ast_mutex_lock(&vms->lock);
04697 if (box == 1) {
04698 mail_setflag(vms->mailstream, sequence, "\\Seen");
04699 } else if (box == 0) {
04700 mail_clearflag(vms->mailstream, sequence, "\\Seen");
04701 }
04702 if (!strcasecmp(mbox(0), vms->curbox) && (box == 0 || box == 1)) {
04703 ast_mutex_unlock(&vms->lock);
04704 return 0;
04705 } else {
04706 int res = !mail_copy(vms->mailstream,sequence,(char *) mbox(box));
04707 ast_mutex_unlock(&vms->lock);
04708 return res;
04709 }
04710 #else
04711 char *dir = vms->curdir;
04712 char *username = vms->username;
04713 char *context = vmu->context;
04714 char sfn[PATH_MAX];
04715 char dfn[PATH_MAX];
04716 char ddir[PATH_MAX];
04717 const char *dbox = mbox(box);
04718 int x;
04719 make_file(sfn, sizeof(sfn), dir, msg);
04720 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
04721
04722 if (vm_lock_path(ddir))
04723 return ERROR_LOCK_PATH;
04724
04725 for (x = 0; x < vmu->maxmsg; x++) {
04726 make_file(dfn, sizeof(dfn), ddir, x);
04727 if (!EXISTS(ddir, x, dfn, NULL))
04728 break;
04729 }
04730 if (x >= vmu->maxmsg) {
04731 ast_unlock_path(ddir);
04732 return ERROR_MAILBOX_FULL;
04733 }
04734 if (strcmp(sfn, dfn)) {
04735 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
04736 }
04737 ast_unlock_path(ddir);
04738 #endif
04739 return 0;
04740 }
04741
04742 static int adsi_logo(unsigned char *buf)
04743 {
04744 int bytes = 0;
04745 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
04746 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
04747 return bytes;
04748 }
04749
04750 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
04751 {
04752 unsigned char buf[256];
04753 int bytes=0;
04754 int x;
04755 char num[5];
04756
04757 *useadsi = 0;
04758 bytes += ast_adsi_data_mode(buf + bytes);
04759 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04760
04761 bytes = 0;
04762 bytes += adsi_logo(buf);
04763 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04764 #ifdef DISPLAY
04765 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
04766 #endif
04767 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04768 bytes += ast_adsi_data_mode(buf + bytes);
04769 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04770
04771 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
04772 bytes = 0;
04773 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
04774 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04775 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04776 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04777 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04778 return 0;
04779 }
04780
04781 #ifdef DISPLAY
04782
04783 bytes = 0;
04784 bytes += ast_adsi_logo(buf);
04785 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04786 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
04787 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04788 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04789 #endif
04790 bytes = 0;
04791 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
04792 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
04793 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
04794 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
04795 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
04796 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
04797 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04798
04799 #ifdef DISPLAY
04800
04801 bytes = 0;
04802 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
04803 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04804
04805 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04806 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04807 #endif
04808
04809 bytes = 0;
04810
04811 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
04812 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
04813 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
04814 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
04815 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
04816 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
04817 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04818
04819 #ifdef DISPLAY
04820
04821 bytes = 0;
04822 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
04823 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04824 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04825 #endif
04826
04827 bytes = 0;
04828 for (x=0;x<5;x++) {
04829 snprintf(num, sizeof(num), "%d", x);
04830 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
04831 }
04832 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
04833 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04834
04835 #ifdef DISPLAY
04836
04837 bytes = 0;
04838 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
04839 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04840 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04841 #endif
04842
04843 if (ast_adsi_end_download(chan)) {
04844 bytes = 0;
04845 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
04846 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04847 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04848 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04849 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04850 return 0;
04851 }
04852 bytes = 0;
04853 bytes += ast_adsi_download_disconnect(buf + bytes);
04854 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04855 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04856
04857 if (option_debug)
04858 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
04859
04860 #ifdef DISPLAY
04861
04862 bytes = 0;
04863 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
04864 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04865 #endif
04866 if (option_debug)
04867 ast_log(LOG_DEBUG, "Restarting session...\n");
04868
04869 bytes = 0;
04870
04871 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
04872 *useadsi = 1;
04873 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
04874 } else
04875 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
04876
04877 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04878 return 0;
04879 }
04880
04881 static void adsi_begin(struct ast_channel *chan, int *useadsi)
04882 {
04883 int x;
04884 if (!ast_adsi_available(chan))
04885 return;
04886 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
04887 if (x < 0)
04888 return;
04889 if (!x) {
04890 if (adsi_load_vmail(chan, useadsi)) {
04891 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
04892 return;
04893 }
04894 } else
04895 *useadsi = 1;
04896 }
04897
04898 static void adsi_login(struct ast_channel *chan)
04899 {
04900 unsigned char buf[256];
04901 int bytes=0;
04902 unsigned char keys[8];
04903 int x;
04904 if (!ast_adsi_available(chan))
04905 return;
04906
04907 for (x=0;x<8;x++)
04908 keys[x] = 0;
04909
04910 keys[3] = ADSI_KEY_APPS + 3;
04911
04912 bytes += adsi_logo(buf + bytes);
04913 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
04914 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
04915 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04916 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
04917 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
04918 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
04919 bytes += ast_adsi_set_keys(buf + bytes, keys);
04920 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04921 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04922 }
04923
04924 static void adsi_password(struct ast_channel *chan)
04925 {
04926 unsigned char buf[256];
04927 int bytes=0;
04928 unsigned char keys[8];
04929 int x;
04930 if (!ast_adsi_available(chan))
04931 return;
04932
04933 for (x=0;x<8;x++)
04934 keys[x] = 0;
04935
04936 keys[3] = ADSI_KEY_APPS + 3;
04937
04938 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04939 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
04940 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
04941 bytes += ast_adsi_set_keys(buf + bytes, keys);
04942 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04943 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04944 }
04945
04946 static void adsi_folders(struct ast_channel *chan, int start, char *label)
04947 {
04948 unsigned char buf[256];
04949 int bytes=0;
04950 unsigned char keys[8];
04951 int x,y;
04952
04953 if (!ast_adsi_available(chan))
04954 return;
04955
04956 for (x=0;x<5;x++) {
04957 y = ADSI_KEY_APPS + 12 + start + x;
04958 if (y > ADSI_KEY_APPS + 12 + 4)
04959 y = 0;
04960 keys[x] = ADSI_KEY_SKT | y;
04961 }
04962 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
04963 keys[6] = 0;
04964 keys[7] = 0;
04965
04966 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
04967 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
04968 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04969 bytes += ast_adsi_set_keys(buf + bytes, keys);
04970 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04971
04972 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04973 }
04974
04975 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
04976 {
04977 int bytes=0;
04978 unsigned char buf[256];
04979 char buf1[256], buf2[256];
04980 char fn2[PATH_MAX];
04981
04982 char cid[256]="";
04983 char *val;
04984 char *name, *num;
04985 char datetime[21]="";
04986 FILE *f;
04987
04988 unsigned char keys[8];
04989
04990 int x;
04991
04992 if (!ast_adsi_available(chan))
04993 return;
04994
04995
04996 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
04997 f = fopen(fn2, "r");
04998 if (f) {
04999 while (!feof(f)) {
05000 if (!fgets((char *)buf, sizeof(buf), f)) {
05001 continue;
05002 }
05003 if (!feof(f)) {
05004 char *stringp=NULL;
05005 stringp = (char *)buf;
05006 strsep(&stringp, "=");
05007 val = strsep(&stringp, "=");
05008 if (!ast_strlen_zero(val)) {
05009 if (!strcmp((char *)buf, "callerid"))
05010 ast_copy_string(cid, val, sizeof(cid));
05011 if (!strcmp((char *)buf, "origdate"))
05012 ast_copy_string(datetime, val, sizeof(datetime));
05013 }
05014 }
05015 }
05016 fclose(f);
05017 }
05018
05019 for (x=0;x<5;x++)
05020 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05021 keys[6] = 0x0;
05022 keys[7] = 0x0;
05023
05024 if (!vms->curmsg) {
05025
05026 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05027 }
05028 if (vms->curmsg >= vms->lastmsg) {
05029
05030 if (vms->curmsg) {
05031
05032 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05033 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05034
05035 } else {
05036
05037 keys[3] = 1;
05038 }
05039 }
05040
05041 if (!ast_strlen_zero(cid)) {
05042 ast_callerid_parse(cid, &name, &num);
05043 if (!name)
05044 name = num;
05045 } else
05046 name = "Unknown Caller";
05047
05048
05049
05050 if (vms->deleted[vms->curmsg])
05051 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05052
05053
05054 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05055 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
05056 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
05057 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
05058
05059 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05060 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05061 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
05062 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
05063 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05064 bytes += ast_adsi_set_keys(buf + bytes, keys);
05065 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05066
05067 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05068 }
05069
05070 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
05071 {
05072 int bytes=0;
05073 unsigned char buf[256];
05074 unsigned char keys[8];
05075
05076 int x;
05077
05078 if (!ast_adsi_available(chan))
05079 return;
05080
05081
05082 for (x=0;x<5;x++)
05083 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05084
05085 keys[6] = 0x0;
05086 keys[7] = 0x0;
05087
05088 if (!vms->curmsg) {
05089
05090 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05091 }
05092 if (vms->curmsg >= vms->lastmsg) {
05093
05094 if (vms->curmsg) {
05095
05096 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05097 } else {
05098
05099 keys[3] = 1;
05100 }
05101 }
05102
05103
05104 if (vms->deleted[vms->curmsg])
05105 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05106
05107
05108 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05109 bytes += ast_adsi_set_keys(buf + bytes, keys);
05110 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05111
05112 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05113 }
05114
05115 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
05116 {
05117 unsigned char buf[256] = "";
05118 char buf1[256] = "", buf2[256] = "";
05119 int bytes=0;
05120 unsigned char keys[8];
05121 int x;
05122
05123 char *newm = (vms->newmessages == 1) ? "message" : "messages";
05124 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
05125 if (!ast_adsi_available(chan))
05126 return;
05127 if (vms->newmessages) {
05128 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
05129 if (vms->oldmessages) {
05130 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
05131 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
05132 } else {
05133 snprintf(buf2, sizeof(buf2), "%s.", newm);
05134 }
05135 } else if (vms->oldmessages) {
05136 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
05137 snprintf(buf2, sizeof(buf2), "%s.", oldm);
05138 } else {
05139 strcpy(buf1, "You have no messages.");
05140 buf2[0] = ' ';
05141 buf2[1] = '\0';
05142 }
05143 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05144 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05145 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05146
05147 for (x=0;x<6;x++)
05148 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
05149 keys[6] = 0;
05150 keys[7] = 0;
05151
05152
05153 if (vms->lastmsg < 0)
05154 keys[0] = 1;
05155 bytes += ast_adsi_set_keys(buf + bytes, keys);
05156
05157 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05158
05159 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05160 }
05161
05162 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
05163 {
05164 unsigned char buf[256] = "";
05165 char buf1[256] = "", buf2[256] = "";
05166 int bytes=0;
05167 unsigned char keys[8];
05168 int x;
05169
05170 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
05171
05172 if (!ast_adsi_available(chan))
05173 return;
05174
05175
05176 for (x=0;x<6;x++)
05177 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
05178
05179 keys[6] = 0;
05180 keys[7] = 0;
05181
05182 if ((vms->lastmsg + 1) < 1)
05183 keys[0] = 0;
05184
05185 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
05186 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
05187
05188 if (vms->lastmsg + 1)
05189 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
05190 else
05191 strcpy(buf2, "no messages.");
05192 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05193 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05194 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
05195 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05196 bytes += ast_adsi_set_keys(buf + bytes, keys);
05197
05198 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05199
05200 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05201
05202 }
05203
05204
05205
05206
05207
05208
05209
05210
05211
05212
05213
05214
05215
05216
05217
05218 static void adsi_goodbye(struct ast_channel *chan)
05219 {
05220 unsigned char buf[256];
05221 int bytes=0;
05222
05223 if (!ast_adsi_available(chan))
05224 return;
05225 bytes += adsi_logo(buf + bytes);
05226 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
05227 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
05228 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05229 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05230
05231 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05232 }
05233
05234
05235
05236
05237
05238 static int get_folder(struct ast_channel *chan, int start)
05239 {
05240 int x;
05241 int d;
05242 char fn[PATH_MAX];
05243 d = ast_play_and_wait(chan, "vm-press");
05244 if (d)
05245 return d;
05246 for (x = start; x< 5; x++) {
05247 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL)))
05248 return d;
05249 d = ast_play_and_wait(chan, "vm-for");
05250 if (d)
05251 return d;
05252 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
05253 d = vm_play_folder_name(chan, fn);
05254 if (d)
05255 return d;
05256 d = ast_waitfordigit(chan, 500);
05257 if (d)
05258 return d;
05259 }
05260 d = ast_play_and_wait(chan, "vm-tocancel");
05261 if (d)
05262 return d;
05263 d = ast_waitfordigit(chan, 4000);
05264 return d;
05265 }
05266
05267 static int get_folder2(struct ast_channel *chan, char *fn, int start)
05268 {
05269 int res = 0;
05270 int loops = 0;
05271 res = ast_play_and_wait(chan, fn);
05272 while (((res < '0') || (res > '9')) &&
05273 (res != '#') && (res >= 0) &&
05274 loops < 4) {
05275 res = get_folder(chan, 0);
05276 loops++;
05277 }
05278 if (loops == 4) {
05279 return '#';
05280 }
05281 return res;
05282 }
05283
05284 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfmts,
05285 char *context, signed char record_gain, long *duration, struct vm_state *vms)
05286 {
05287 int cmd = 0;
05288 int retries = 0, prepend_duration = 0, already_recorded = 0;
05289 signed char zero_gain = 0;
05290 struct ast_config *msg_cfg;
05291 const char *duration_cstr;
05292 char msgfile[PATH_MAX], backup[PATH_MAX];
05293 char textfile[PATH_MAX];
05294 char backup_textfile[PATH_MAX];
05295 struct ast_category *msg_cat;
05296 char duration_str[12] = "";
05297
05298 ast_log(LOG_NOTICE, "curdir=%s\n", curdir);
05299
05300 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
05301 strcpy(textfile, msgfile);
05302 strcpy(backup, msgfile);
05303 strcpy(backup_textfile, msgfile);
05304 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
05305 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
05306 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
05307
05308 if (!(msg_cfg = ast_config_load(textfile))) {
05309 return -1;
05310 }
05311
05312 *duration = 0;
05313 if ((duration_cstr = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
05314 *duration = atoi(duration_cstr);
05315 }
05316
05317 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
05318 if (cmd)
05319 retries = 0;
05320 switch (cmd) {
05321 case '1':
05322
05323 {
05324 prepend_duration = 0;
05325
05326
05327 #ifndef IMAP_STORAGE
05328 if (already_recorded) {
05329 ast_filecopy(backup, msgfile, NULL);
05330 copy(textfile, backup_textfile);
05331 } else {
05332 ast_filecopy(msgfile, backup, NULL);
05333 copy(textfile, backup_textfile);
05334 }
05335 #endif
05336 already_recorded = 1;
05337
05338 if (record_gain)
05339 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
05340
05341 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vmfmts, &prepend_duration, 1, silencethreshold, maxsilence);
05342 if (cmd == 'S') {
05343 ast_filerename(backup, msgfile, NULL);
05344 }
05345
05346 if (record_gain)
05347 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
05348
05349 if (prepend_duration) {
05350 prepend_duration += *duration;
05351 }
05352
05353 break;
05354 }
05355 case '2':
05356 cmd = 't';
05357 break;
05358 case '*':
05359 cmd = '*';
05360 break;
05361 default:
05362 cmd = ast_play_and_wait(chan,"vm-forwardoptions");
05363
05364 if (!cmd)
05365 cmd = ast_play_and_wait(chan,"vm-starmain");
05366
05367 if (!cmd)
05368 cmd = ast_waitfordigit(chan,6000);
05369 if (!cmd)
05370 retries++;
05371 if (retries > 3)
05372 cmd = 't';
05373 }
05374 }
05375
05376 if (already_recorded && cmd == -1) {
05377
05378 ast_filerename(backup, msgfile, NULL);
05379 if (duration_cstr) {
05380 ast_copy_string(duration_str, duration_cstr, sizeof(duration_str));
05381 }
05382 } else if (prepend_duration) {
05383 *duration = prepend_duration;
05384 snprintf(duration_str, sizeof(duration_str), "%d", prepend_duration);
05385 }
05386
05387 msg_cat = ast_category_get(msg_cfg, "message");
05388 if (!ast_strlen_zero(duration_str) && !ast_variable_update(msg_cat, "duration", duration_str, NULL, 0)) {
05389 config_text_file_save(textfile, msg_cfg, "app_voicemail");
05390 }
05391 ast_config_destroy(msg_cfg);
05392
05393 if (cmd == 't' || cmd == 'S')
05394 cmd = 0;
05395 return cmd;
05396 }
05397
05398 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname)
05399 {
05400 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
05401 int newmsgs = 0, oldmsgs = 0;
05402 const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
05403
05404 #ifndef IMAP_STORAGE
05405 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
05406 #else
05407 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
05408 #endif
05409 make_file(fn, sizeof(fn), todir, msgnum);
05410 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
05411
05412 if (!ast_strlen_zero(vmu->attachfmt)) {
05413 if (strstr(fmt, vmu->attachfmt)) {
05414 fmt = vmu->attachfmt;
05415 } else {
05416 ast_log(LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'. Falling back to default format for '%s@%s'.\n", vmu->attachfmt, fmt, vmu->mailbox, vmu->context);
05417 }
05418 }
05419
05420
05421 fmt = ast_strdupa(fmt);
05422 stringp = fmt;
05423 strsep(&stringp, "|");
05424
05425 if (!ast_strlen_zero(vmu->email)) {
05426 int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
05427 char *myserveremail = serveremail;
05428 attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
05429 if (!ast_strlen_zero(vmu->serveremail))
05430 myserveremail = vmu->serveremail;
05431
05432 if (attach_user_voicemail)
05433 RETRIEVE(todir, msgnum, vmu);
05434
05435
05436 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category);
05437
05438 if (attach_user_voicemail)
05439 DISPOSE(todir, msgnum);
05440 }
05441
05442 if (!ast_strlen_zero(vmu->pager)) {
05443 char *myserveremail = serveremail;
05444 if (!ast_strlen_zero(vmu->serveremail))
05445 myserveremail = vmu->serveremail;
05446 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, duration, vmu, category);
05447 }
05448
05449 if (ast_test_flag(vmu, VM_DELETE)) {
05450 DELETE(todir, msgnum, fn, vmu);
05451 }
05452
05453
05454 if (ast_app_has_voicemail(ext_context, NULL)) {
05455 ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs);
05456 }
05457 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
05458 run_externnotify(vmu->context, vmu->mailbox);
05459 return 0;
05460 }
05461
05462 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain)
05463 {
05464 #ifdef IMAP_STORAGE
05465 int todircount=0;
05466 struct vm_state *dstvms;
05467 #else
05468 char textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
05469 #endif
05470 char username[70]="";
05471 int res = 0, cmd = 0;
05472 struct ast_vm_user *receiver = NULL, *vmtmp;
05473 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
05474 char *stringp;
05475 const char *s;
05476 int saved_messages = 0;
05477 int valid_extensions = 0;
05478 char *dir;
05479 int curmsg;
05480 int prompt_played = 0;
05481
05482 if (vms == NULL) return -1;
05483 dir = vms->curdir;
05484 curmsg = vms->curmsg;
05485
05486 while (!res && !valid_extensions) {
05487 int use_directory = 0;
05488 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
05489 int done = 0;
05490 int retries = 0;
05491 cmd=0;
05492 while ((cmd >= 0) && !done ){
05493 if (cmd)
05494 retries = 0;
05495 switch (cmd) {
05496 case '1':
05497 use_directory = 0;
05498 done = 1;
05499 break;
05500 case '2':
05501 use_directory = 1;
05502 done=1;
05503 break;
05504 case '*':
05505 cmd = 't';
05506 done = 1;
05507 break;
05508 default:
05509
05510 cmd = ast_play_and_wait(chan,"vm-forward");
05511 if (!cmd)
05512 cmd = ast_waitfordigit(chan,3000);
05513 if (!cmd)
05514 retries++;
05515 if (retries > 3)
05516 {
05517 cmd = 't';
05518 done = 1;
05519 }
05520
05521 }
05522 }
05523 if (cmd < 0 || cmd == 't')
05524 break;
05525 }
05526
05527 if (use_directory) {
05528
05529
05530 char old_context[sizeof(chan->context)];
05531 char old_exten[sizeof(chan->exten)];
05532 int old_priority;
05533 struct ast_app* app;
05534
05535
05536 app = pbx_findapp("Directory");
05537 if (app) {
05538 char vmcontext[256];
05539
05540 memcpy(old_context, chan->context, sizeof(chan->context));
05541 memcpy(old_exten, chan->exten, sizeof(chan->exten));
05542 old_priority = chan->priority;
05543
05544
05545 snprintf(vmcontext, sizeof(vmcontext), "%s||v", context ? context : "default");
05546 res = pbx_exec(chan, app, vmcontext);
05547
05548 ast_copy_string(username, chan->exten, sizeof(username));
05549
05550
05551 memcpy(chan->context, old_context, sizeof(chan->context));
05552 memcpy(chan->exten, old_exten, sizeof(chan->exten));
05553 chan->priority = old_priority;
05554
05555 } else {
05556 ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
05557 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
05558 }
05559 } else {
05560
05561 res = ast_streamfile(chan, "vm-extension", chan->language);
05562 prompt_played++;
05563 if (res || prompt_played > 4)
05564 break;
05565 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
05566 break;
05567 }
05568
05569
05570 if (ast_strlen_zero(username))
05571 continue;
05572 stringp = username;
05573 s = strsep(&stringp, "*");
05574
05575 valid_extensions = 1;
05576 while (s) {
05577
05578 if ((is_new_message == 1 || strcmp(s,sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
05579 int oldmsgs;
05580 int newmsgs;
05581 int capacity;
05582 if (inboxcount(s, &newmsgs, &oldmsgs)) {
05583 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
05584
05585 res = ast_play_and_wait(chan, "pbx-invalid");
05586 valid_extensions = 0;
05587 break;
05588 }
05589 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
05590 if ((newmsgs + oldmsgs) >= capacity) {
05591 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
05592 res = ast_play_and_wait(chan, "vm-mailboxfull");
05593 valid_extensions = 0;
05594 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
05595 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
05596 free_user(vmtmp);
05597 }
05598 inprocess_count(receiver->mailbox, receiver->context, -1);
05599 break;
05600 }
05601 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
05602 } else {
05603 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
05604
05605 res = ast_play_and_wait(chan, "pbx-invalid");
05606 valid_extensions = 0;
05607 break;
05608 }
05609 s = strsep(&stringp, "*");
05610 }
05611
05612 if (valid_extensions)
05613 break;
05614 }
05615
05616 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
05617 return res;
05618 if (is_new_message == 1) {
05619 struct leave_vm_options leave_options;
05620 char mailbox[AST_MAX_EXTENSION * 2 + 2];
05621
05622 if (context)
05623 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
05624 else
05625 ast_copy_string(mailbox, username, sizeof(mailbox));
05626
05627
05628 memset(&leave_options, 0, sizeof(leave_options));
05629 leave_options.record_gain = record_gain;
05630 cmd = leave_voicemail(chan, mailbox, &leave_options);
05631 } else {
05632
05633 long duration = 0;
05634 struct vm_state vmstmp;
05635 #ifndef IMAP_STORAGE
05636 char msgfile[PATH_MAX];
05637 #endif
05638 int copy_msg_result = 0;
05639
05640 memcpy(&vmstmp, vms, sizeof(vmstmp));
05641
05642 RETRIEVE(dir, curmsg, sender);
05643
05644 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp);
05645 if (!cmd) {
05646 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
05647 #ifdef IMAP_STORAGE
05648 char *myserveremail;
05649 int attach_user_voicemail;
05650
05651 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
05652 if (!dstvms) {
05653 dstvms = create_vm_state_from_user(vmtmp);
05654 }
05655 if (dstvms) {
05656 init_mailstream(dstvms, 0);
05657 if (!dstvms->mailstream) {
05658 ast_log (LOG_ERROR,"IMAP mailstream for %s is NULL\n",vmtmp->mailbox);
05659 } else {
05660 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms);
05661 run_externnotify(vmtmp->context, vmtmp->mailbox);
05662 }
05663 } else {
05664 ast_log (LOG_ERROR,"Could not find state information for mailbox %s\n",vmtmp->mailbox);
05665 }
05666 myserveremail = serveremail;
05667 if (!ast_strlen_zero(vmtmp->serveremail))
05668 myserveremail = vmtmp->serveremail;
05669 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
05670
05671 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, dstvms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vms->fn, fmt, duration, attach_user_voicemail, chan, NULL);
05672 #else
05673 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir);
05674 #endif
05675 saved_messages++;
05676 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
05677 AST_LIST_REMOVE_CURRENT(&extensions, list);
05678 free_user(vmtmp);
05679 if (res)
05680 break;
05681 }
05682 AST_LIST_TRAVERSE_SAFE_END;
05683 if (saved_messages > 0 && !copy_msg_result) {
05684
05685
05686
05687
05688
05689
05690
05691
05692 res = ast_play_and_wait(chan, "vm-msgsaved");
05693 }
05694 #ifndef IMAP_STORAGE
05695 else {
05696
05697 res = ast_play_and_wait(chan, "vm-mailboxfull");
05698 }
05699
05700 make_file(msgfile, sizeof(msgfile), dir, curmsg);
05701 strcpy(textfile, msgfile);
05702 strcpy(backup, msgfile);
05703 strcpy(backup_textfile, msgfile);
05704 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
05705 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
05706 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
05707 if (ast_fileexists(backup, NULL, NULL) > 0) {
05708 ast_filerename(backup, msgfile, NULL);
05709 rename(backup_textfile, textfile);
05710 }
05711 #endif
05712 }
05713 DISPOSE(dir, curmsg);
05714 #ifndef IMAP_STORAGE
05715 if (cmd) {
05716 make_file(msgfile, sizeof(msgfile), dir, curmsg);
05717 strcpy(textfile, msgfile);
05718 strcpy(backup_textfile, msgfile);
05719 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
05720 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
05721 rename(backup_textfile, textfile);
05722 }
05723 #endif
05724 }
05725
05726
05727 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
05728 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
05729 free_user(vmtmp);
05730 }
05731 return res ? res : cmd;
05732 }
05733
05734 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
05735 {
05736 int res;
05737 if ((res = ast_stream_and_wait(chan, file, chan->language, AST_DIGIT_ANY)) < 0)
05738 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
05739 return res;
05740 }
05741
05742 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
05743 {
05744 return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", "2", skipms);
05745 }
05746
05747 static int play_message_category(struct ast_channel *chan, const char *category)
05748 {
05749 int res = 0;
05750
05751 if (!ast_strlen_zero(category))
05752 res = ast_play_and_wait(chan, category);
05753
05754 if (res) {
05755 ast_log(LOG_WARNING, "No sound file for category '%s' was found.\n", category);
05756 res = 0;
05757 }
05758
05759 return res;
05760 }
05761
05762 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
05763 {
05764 int res = 0;
05765 struct vm_zone *the_zone = NULL;
05766 time_t t;
05767
05768 if (ast_get_time_t(origtime, &t, 0, NULL)) {
05769 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
05770 return 0;
05771 }
05772
05773
05774 if (!ast_strlen_zero(vmu->zonetag)) {
05775
05776 struct vm_zone *z;
05777 AST_LIST_LOCK(&zones);
05778 AST_LIST_TRAVERSE(&zones, z, list) {
05779 if (!strcmp(z->name, vmu->zonetag)) {
05780 the_zone = z;
05781 break;
05782 }
05783 }
05784 AST_LIST_UNLOCK(&zones);
05785 }
05786
05787
05788 #if 0
05789
05790 ast_localtime(&t, &time_now, NULL);
05791 tv_now = ast_tvnow();
05792 tnow = tv_now.tv_sec;
05793 ast_localtime(&tnow, &time_then, NULL);
05794
05795
05796 if (time_now.tm_year == time_then.tm_year)
05797 snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
05798 else
05799 snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
05800 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
05801
05802
05803 #endif
05804 if (the_zone) {
05805 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
05806 } else if (!strncasecmp(chan->language, "de", 2)) {
05807 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05808 } else if (!strncasecmp(chan->language, "gr", 2)) {
05809 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
05810 } else if (!strncasecmp(chan->language, "he", 2)) {
05811 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'at2' kM", NULL);
05812 } else if (!strncasecmp(chan->language, "it", 2)) {
05813 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
05814 } else if (!strncasecmp(chan->language, "nl", 2)) {
05815 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
05816 } else if (!strncasecmp(chan->language, "no", 2)) {
05817 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05818 } else if (!strncasecmp(chan->language, "pl", 2)) {
05819 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
05820 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
05821 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL);
05822 } else if (!strncasecmp(chan->language, "se", 2)) {
05823 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
05824 } else {
05825 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
05826 }
05827 #if 0
05828 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
05829 #endif
05830 return res;
05831 }
05832
05833
05834
05835 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
05836 {
05837 int res = 0;
05838 int i;
05839 char *callerid, *name;
05840 char prefile[PATH_MAX] = "";
05841
05842
05843
05844
05845 if ((cid == NULL)||(context == NULL))
05846 return res;
05847
05848
05849 if (option_debug > 2)
05850 ast_log(LOG_DEBUG, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
05851 ast_callerid_parse(cid, &name, &callerid);
05852 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
05853
05854
05855 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
05856 if (option_debug > 2)
05857 ast_log(LOG_DEBUG, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
05858 if ((strcmp(cidinternalcontexts[i], context) == 0))
05859 break;
05860 }
05861 if (i != MAX_NUM_CID_CONTEXTS){
05862 if (!res) {
05863 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
05864 if (!ast_strlen_zero(prefile)) {
05865
05866 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05867 if (option_verbose > 2)
05868 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
05869 if (!callback)
05870 res = wait_file2(chan, vms, "vm-from");
05871 res = ast_stream_and_wait(chan, prefile, chan->language, "");
05872 } else {
05873 if (option_verbose > 2)
05874 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: message from '%s'\n", callerid);
05875
05876 if (!callback)
05877 res = wait_file2(chan, vms, "vm-from-extension");
05878 res = ast_say_digit_str(chan, callerid, "", chan->language);
05879 }
05880 }
05881 }
05882 }
05883
05884 else if (!res){
05885 if (option_debug > 2)
05886 ast_log(LOG_DEBUG, "VM-CID: Numeric caller id: (%s)\n",callerid);
05887
05888 if (!callback)
05889 res = wait_file2(chan, vms, "vm-from-phonenumber");
05890 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
05891 }
05892 } else {
05893
05894 if (option_debug)
05895 ast_log(LOG_DEBUG, "VM-CID: From an unknown number\n");
05896
05897 res = wait_file2(chan, vms, "vm-unknown-caller");
05898 }
05899 return res;
05900 }
05901
05902 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
05903 {
05904 int res = 0;
05905 int durationm;
05906 int durations;
05907
05908 if (duration == NULL)
05909 return res;
05910
05911
05912 durations=atoi(duration);
05913 durationm=(durations / 60);
05914
05915 if (option_debug > 2)
05916 ast_log(LOG_DEBUG, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
05917
05918 if ((!res) && (durationm >= minduration)) {
05919 res = wait_file2(chan, vms, "vm-duration");
05920
05921
05922 if (!strncasecmp(chan->language, "pl", 2)) {
05923 div_t num = div(durationm, 10);
05924
05925 if (durationm == 1) {
05926 res = ast_play_and_wait(chan, "digits/1z");
05927 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
05928 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
05929 if (num.rem == 2) {
05930 if (!num.quot) {
05931 res = ast_play_and_wait(chan, "digits/2-ie");
05932 } else {
05933 res = say_and_wait(chan, durationm - 2 , chan->language);
05934 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
05935 }
05936 } else {
05937 res = say_and_wait(chan, durationm, chan->language);
05938 }
05939 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
05940 } else {
05941 res = say_and_wait(chan, durationm, chan->language);
05942 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
05943 }
05944
05945 } else {
05946 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
05947 res = wait_file2(chan, vms, "vm-minutes");
05948 }
05949 }
05950 return res;
05951 }
05952
05953 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
05954 {
05955 int res = 0;
05956 char filename[256], *cid;
05957 const char *origtime, *context, *category, *duration;
05958 struct ast_config *msg_cfg;
05959
05960 vms->starting = 0;
05961 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
05962 adsi_message(chan, vms);
05963
05964 if (!strncasecmp(chan->language, "he", 2)) {
05965
05966
05967
05968
05969 if (!vms->curmsg) {
05970 res = wait_file2(chan, vms, "vm-message");
05971 res = wait_file2(chan, vms, "vm-first");
05972 } else if (vms->curmsg == vms->lastmsg) {
05973 res = wait_file2(chan, vms, "vm-message");
05974 res = wait_file2(chan, vms, "vm-last");
05975 } else {
05976 res = wait_file2(chan, vms, "vm-message");
05977 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05978 ast_log(LOG_DEBUG, "curmsg: %d\n", vms->curmsg);
05979 ast_log(LOG_DEBUG, "lagmsg: %d\n", vms->lastmsg);
05980 if (!res) {
05981 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
05982 }
05983 }
05984 }
05985
05986 } else if (!strncasecmp(chan->language, "pl", 2)) {
05987 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05988 int ten, one;
05989 char nextmsg[256];
05990 ten = (vms->curmsg + 1) / 10;
05991 one = (vms->curmsg + 1) % 10;
05992
05993 if (vms->curmsg < 20) {
05994 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
05995 res = wait_file2(chan, vms, nextmsg);
05996 } else {
05997 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
05998 res = wait_file2(chan, vms, nextmsg);
05999 if (one > 0) {
06000 if (!res) {
06001 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
06002 res = wait_file2(chan, vms, nextmsg);
06003 }
06004 }
06005 }
06006 }
06007 if (!res)
06008 res = wait_file2(chan, vms, "vm-message");
06009
06010 } else if (!strncasecmp(chan->language, "se", 2)) {
06011 if (!vms->curmsg)
06012 res = wait_file2(chan, vms, "vm-first");
06013 else if (vms->curmsg == vms->lastmsg)
06014 res = wait_file2(chan, vms, "vm-last");
06015 res = wait_file2(chan, vms, "vm-meddelandet");
06016 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
06017 if (!res)
06018 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
06019 }
06020
06021
06022
06023
06024
06025 } else {
06026 if (!vms->curmsg)
06027 res = wait_file2(chan, vms, "vm-first");
06028 else if (vms->curmsg == vms->lastmsg)
06029 res = wait_file2(chan, vms, "vm-last");
06030 res = wait_file2(chan, vms, "vm-message");
06031 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
06032 if (!res)
06033 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
06034 }
06035 }
06036
06037
06038 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
06039 snprintf(filename, sizeof(filename), "%s.txt", vms->fn2);
06040 RETRIEVE(vms->curdir, vms->curmsg, vmu);
06041 msg_cfg = ast_config_load(filename);
06042 if (!msg_cfg) {
06043 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
06044 return 0;
06045 }
06046
06047 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
06048 ast_log(LOG_WARNING, "No origtime?!\n");
06049 DISPOSE(vms->curdir, vms->curmsg);
06050 ast_config_destroy(msg_cfg);
06051 return 0;
06052 }
06053
06054 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
06055 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
06056 category = ast_variable_retrieve(msg_cfg, "message", "category");
06057
06058 context = ast_variable_retrieve(msg_cfg, "message", "context");
06059 if (!strncasecmp("macro",context,5))
06060 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
06061 if (!res)
06062 res = play_message_category(chan, category);
06063 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
06064 res = play_message_datetime(chan, vmu, origtime, filename);
06065 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
06066 res = play_message_callerid(chan, vms, cid, context, 0);
06067 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
06068 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
06069
06070 if (res == '1')
06071 res = 0;
06072 ast_config_destroy(msg_cfg);
06073
06074 if (!res) {
06075 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
06076 vms->heard[vms->curmsg] = 1;
06077 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
06078 ast_log(LOG_WARNING, "Playback of message %s failed\n", vms->fn);
06079 res = 0;
06080 }
06081 }
06082 DISPOSE(vms->curdir, vms->curmsg);
06083 return res;
06084 }
06085
06086 #ifndef IMAP_STORAGE
06087 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
06088 {
06089 int count_msg, last_msg;
06090
06091 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
06092
06093
06094
06095
06096 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
06097
06098
06099 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
06100
06101
06102 count_msg = count_messages(vmu, vms->curdir);
06103 if (count_msg < 0)
06104 return count_msg;
06105 else
06106 vms->lastmsg = count_msg - 1;
06107
06108 if (vm_allocate_dh(vms, vmu, count_msg)) {
06109 return -1;
06110 }
06111
06112
06113
06114
06115
06116
06117
06118
06119
06120 last_msg = last_message_index(vmu, vms->curdir);
06121
06122 if (last_msg < -1) {
06123 return last_msg;
06124 } else if (vms->lastmsg != last_msg) {
06125 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
06126 resequence_mailbox(vmu, vms->curdir, count_msg);
06127 }
06128
06129 return 0;
06130 }
06131 #endif
06132
06133 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
06134 {
06135 int x = 0;
06136 #ifndef IMAP_STORAGE
06137 int last_msg_index;
06138 int res = 0, nummsg;
06139 #endif
06140
06141 if (vms->lastmsg <= -1)
06142 goto done;
06143
06144 vms->curmsg = -1;
06145 #ifndef IMAP_STORAGE
06146
06147 if (vm_lock_path(vms->curdir))
06148 return ERROR_LOCK_PATH;
06149
06150 last_msg_index = last_message_index(vmu, vms->curdir);
06151 if (last_msg_index != vms->lastmsg) {
06152 ast_log(LOG_NOTICE, "%d messages arrived while mailbox was open\n", last_msg_index - vms->lastmsg);
06153 }
06154
06155
06156 for (x = 0; x < last_msg_index + 1; x++) {
06157 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
06158
06159 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
06160 if (!EXISTS(vms->curdir, x, vms->fn, NULL))
06161 break;
06162 vms->curmsg++;
06163 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
06164 if (strcmp(vms->fn, vms->fn2)) {
06165 RENAME(vms->curdir, x, vmu->mailbox,vmu->context, vms->curdir, vms->curmsg, vms->fn, vms->fn2);
06166 }
06167 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
06168
06169 res = save_to_folder(vmu, vms, x, 1);
06170 if (res == ERROR_LOCK_PATH || res == ERROR_MAILBOX_FULL) {
06171
06172 ast_log(LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
06173 vms->deleted[x] = 0;
06174 vms->heard[x] = 0;
06175 --x;
06176 }
06177 }
06178 }
06179
06180
06181 nummsg = x - 1;
06182 for (x = vms->curmsg + 1; x <= nummsg; x++) {
06183 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
06184 if (EXISTS(vms->curdir, x, vms->fn, NULL))
06185 DELETE(vms->curdir, x, vms->fn, vmu);
06186 }
06187 ast_unlock_path(vms->curdir);
06188 #else
06189 if (vms->deleted) {
06190
06191
06192 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
06193 if (vms->deleted[x]) {
06194 if (option_debug > 2) {
06195 ast_log(LOG_DEBUG, "IMAP delete of %d\n", x);
06196 }
06197 DELETE(vms->curdir, x, vms->fn, vmu);
06198 }
06199 }
06200 }
06201 #endif
06202
06203 done:
06204 if (vms->deleted)
06205 memset(vms->deleted, 0, vms->dh_arraysize * sizeof(int));
06206 if (vms->heard)
06207 memset(vms->heard, 0, vms->dh_arraysize * sizeof(int));
06208
06209 return 0;
06210 }
06211
06212
06213
06214
06215
06216
06217
06218 static int vm_play_folder_name_gr(struct ast_channel *chan, char *mbox)
06219 {
06220 int cmd;
06221 char *buf;
06222
06223 buf = alloca(strlen(mbox)+2);
06224 strcpy(buf, mbox);
06225 strcat(buf,"s");
06226
06227 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")){
06228 cmd = ast_play_and_wait(chan, buf);
06229 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06230 } else {
06231 cmd = ast_play_and_wait(chan, "vm-messages");
06232 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06233 }
06234 }
06235
06236 static int vm_play_folder_name_pl(struct ast_channel *chan, char *mbox)
06237 {
06238 int cmd;
06239
06240 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")) {
06241 if (!strcasecmp(mbox, "vm-INBOX"))
06242 cmd = ast_play_and_wait(chan, "vm-new-e");
06243 else
06244 cmd = ast_play_and_wait(chan, "vm-old-e");
06245 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06246 } else {
06247 cmd = ast_play_and_wait(chan, "vm-messages");
06248 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06249 }
06250 }
06251
06252 static int vm_play_folder_name_ua(struct ast_channel *chan, char *mbox)
06253 {
06254 int cmd;
06255
06256 if (!strcasecmp(mbox, "vm-Family") || !strcasecmp(mbox, "vm-Friends") || !strcasecmp(mbox, "vm-Work")){
06257 cmd = ast_play_and_wait(chan, "vm-messages");
06258 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06259 } else {
06260 cmd = ast_play_and_wait(chan, mbox);
06261 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06262 }
06263 }
06264
06265 static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
06266 {
06267 int cmd;
06268
06269 if ( !strncasecmp(chan->language, "it", 2) ||
06270 !strncasecmp(chan->language, "es", 2) ||
06271 !strncasecmp(chan->language, "pt", 2)) {
06272 cmd = ast_play_and_wait(chan, "vm-messages");
06273 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06274 } else if (!strncasecmp(chan->language, "gr", 2)) {
06275 return vm_play_folder_name_gr(chan, mbox);
06276 } else if (!strncasecmp(chan->language, "pl", 2)) {
06277 return vm_play_folder_name_pl(chan, mbox);
06278 } else if (!strncasecmp(chan->language, "ua", 2)) {
06279 return vm_play_folder_name_ua(chan, mbox);
06280 } else if (!strncasecmp(chan->language, "he", 2)) {
06281 cmd = ast_play_and_wait(chan, mbox);
06282 return cmd;
06283 } else {
06284 cmd = ast_play_and_wait(chan, mbox);
06285 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06286 }
06287 }
06288
06289
06290
06291
06292
06293
06294
06295
06296
06297
06298
06299
06300
06301 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
06302 {
06303 int res = 0;
06304
06305 if (vms->newmessages) {
06306 res = ast_play_and_wait(chan, "vm-youhave");
06307 if (!res)
06308 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
06309 if (!res) {
06310 if ((vms->newmessages == 1)) {
06311 res = ast_play_and_wait(chan, "vm-INBOX");
06312 if (!res)
06313 res = ast_play_and_wait(chan, "vm-message");
06314 } else {
06315 res = ast_play_and_wait(chan, "vm-INBOXs");
06316 if (!res)
06317 res = ast_play_and_wait(chan, "vm-messages");
06318 }
06319 }
06320 } else if (vms->oldmessages){
06321 res = ast_play_and_wait(chan, "vm-youhave");
06322 if (!res)
06323 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
06324 if ((vms->oldmessages == 1)){
06325 res = ast_play_and_wait(chan, "vm-Old");
06326 if (!res)
06327 res = ast_play_and_wait(chan, "vm-message");
06328 } else {
06329 res = ast_play_and_wait(chan, "vm-Olds");
06330 if (!res)
06331 res = ast_play_and_wait(chan, "vm-messages");
06332 }
06333 } else if (!vms->oldmessages && !vms->newmessages)
06334 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
06335 return res;
06336 }
06337
06338
06339 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
06340 {
06341 int res;
06342
06343
06344 res = ast_play_and_wait(chan, "vm-youhave");
06345 if (!res) {
06346 if (vms->newmessages) {
06347 res = say_and_wait(chan, vms->newmessages, chan->language);
06348 if (!res)
06349 res = ast_play_and_wait(chan, "vm-INBOX");
06350 if (vms->oldmessages && !res)
06351 res = ast_play_and_wait(chan, "vm-and");
06352 else if (!res) {
06353 if ((vms->newmessages == 1))
06354 res = ast_play_and_wait(chan, "vm-message");
06355 else
06356 res = ast_play_and_wait(chan, "vm-messages");
06357 }
06358
06359 }
06360 if (!res && vms->oldmessages) {
06361 res = say_and_wait(chan, vms->oldmessages, chan->language);
06362 if (!res)
06363 res = ast_play_and_wait(chan, "vm-Old");
06364 if (!res) {
06365 if (vms->oldmessages == 1)
06366 res = ast_play_and_wait(chan, "vm-message");
06367 else
06368 res = ast_play_and_wait(chan, "vm-messages");
06369 }
06370 }
06371 if (!res) {
06372 if (!vms->oldmessages && !vms->newmessages) {
06373 res = ast_play_and_wait(chan, "vm-no");
06374 if (!res)
06375 res = ast_play_and_wait(chan, "vm-messages");
06376 }
06377 }
06378 }
06379 return res;
06380 }
06381
06382
06383
06384
06385
06386
06387
06388
06389
06390
06391
06392
06393
06394
06395
06396
06397
06398
06399
06400
06401
06402
06403
06404
06405
06406
06407
06408
06409
06410
06411
06412
06413
06414
06415
06416
06417
06418
06419
06420
06421
06422
06423
06424
06425
06426
06427
06428
06429
06430
06431
06432
06433
06434
06435
06436
06437
06438
06439 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
06440 {
06441 int res;
06442 int lastnum = 0;
06443
06444 res = ast_play_and_wait(chan, "vm-youhave");
06445
06446 if (!res && vms->newmessages) {
06447 lastnum = vms->newmessages;
06448
06449 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
06450 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
06451 }
06452
06453 if (!res && vms->oldmessages) {
06454 res = ast_play_and_wait(chan, "vm-and");
06455 }
06456 }
06457
06458 if (!res && vms->oldmessages) {
06459 lastnum = vms->oldmessages;
06460
06461 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
06462 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
06463 }
06464 }
06465
06466 if (!res) {
06467 if (lastnum == 0) {
06468 res = ast_play_and_wait(chan, "vm-no");
06469 }
06470 if (!res) {
06471 res = ast_say_counted_noun(chan, lastnum, "vm-message");
06472 }
06473 }
06474
06475 return res;
06476 }
06477
06478
06479 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
06480 {
06481 int res=0;
06482
06483
06484 if (!res) {
06485 if ((vms->newmessages) || (vms->oldmessages)) {
06486 res = ast_play_and_wait(chan, "vm-youhave");
06487 }
06488
06489
06490
06491
06492
06493 if (vms->newmessages) {
06494 if (!res) {
06495 if (vms->newmessages == 1) {
06496 res = ast_play_and_wait(chan, "vm-INBOX1");
06497 } else {
06498 if (vms->newmessages == 2) {
06499 res = ast_play_and_wait(chan, "vm-shtei");
06500 } else {
06501 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06502 }
06503 res = ast_play_and_wait(chan, "vm-INBOX");
06504 }
06505 }
06506 if (vms->oldmessages && !res) {
06507 res = ast_play_and_wait(chan, "vm-and");
06508 if (vms->oldmessages == 1) {
06509 res = ast_play_and_wait(chan, "vm-Old1");
06510 } else {
06511 if (vms->oldmessages == 2) {
06512 res = ast_play_and_wait(chan, "vm-shtei");
06513 } else {
06514 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06515 }
06516 res = ast_play_and_wait(chan, "vm-Old");
06517 }
06518 }
06519 }
06520 if (!res && vms->oldmessages && !vms->newmessages) {
06521 if (!res) {
06522 if (vms->oldmessages == 1) {
06523 res = ast_play_and_wait(chan, "vm-Old1");
06524 } else {
06525 if (vms->oldmessages == 2) {
06526 res = ast_play_and_wait(chan, "vm-shtei");
06527 } else {
06528 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06529 }
06530 res = ast_play_and_wait(chan, "vm-Old");
06531 }
06532 }
06533 }
06534 if (!res) {
06535 if (!vms->oldmessages && !vms->newmessages) {
06536 if (!res) {
06537 res = ast_play_and_wait(chan, "vm-nomessages");
06538 }
06539 }
06540 }
06541 }
06542 return res;
06543 }
06544
06545
06546
06547 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
06548 {
06549
06550 int res;
06551 if (!vms->oldmessages && !vms->newmessages)
06552 res = ast_play_and_wait(chan, "vm-no") ||
06553 ast_play_and_wait(chan, "vm-message");
06554 else
06555 res = ast_play_and_wait(chan, "vm-youhave");
06556 if (!res && vms->newmessages) {
06557 res = (vms->newmessages == 1) ?
06558 ast_play_and_wait(chan, "digits/un") ||
06559 ast_play_and_wait(chan, "vm-nuovo") ||
06560 ast_play_and_wait(chan, "vm-message") :
06561
06562 say_and_wait(chan, vms->newmessages, chan->language) ||
06563 ast_play_and_wait(chan, "vm-nuovi") ||
06564 ast_play_and_wait(chan, "vm-messages");
06565 if (!res && vms->oldmessages)
06566 res = ast_play_and_wait(chan, "vm-and");
06567 }
06568 if (!res && vms->oldmessages) {
06569 res = (vms->oldmessages == 1) ?
06570 ast_play_and_wait(chan, "digits/un") ||
06571 ast_play_and_wait(chan, "vm-vecchio") ||
06572 ast_play_and_wait(chan, "vm-message") :
06573
06574 say_and_wait(chan, vms->oldmessages, chan->language) ||
06575 ast_play_and_wait(chan, "vm-vecchi") ||
06576 ast_play_and_wait(chan, "vm-messages");
06577 }
06578 return res;
06579 }
06580
06581
06582 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
06583 {
06584
06585 int res;
06586 div_t num;
06587
06588 if (!vms->oldmessages && !vms->newmessages) {
06589 res = ast_play_and_wait(chan, "vm-no");
06590 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06591 return res;
06592 } else {
06593 res = ast_play_and_wait(chan, "vm-youhave");
06594 }
06595
06596 if (vms->newmessages) {
06597 num = div(vms->newmessages, 10);
06598 if (vms->newmessages == 1) {
06599 res = ast_play_and_wait(chan, "digits/1-a");
06600 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
06601 res = res ? res : ast_play_and_wait(chan, "vm-message");
06602 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06603 if (num.rem == 2) {
06604 if (!num.quot) {
06605 res = ast_play_and_wait(chan, "digits/2-ie");
06606 } else {
06607 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
06608 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06609 }
06610 } else {
06611 res = say_and_wait(chan, vms->newmessages, chan->language);
06612 }
06613 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
06614 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06615 } else {
06616 res = say_and_wait(chan, vms->newmessages, chan->language);
06617 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
06618 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06619 }
06620 if (!res && vms->oldmessages)
06621 res = ast_play_and_wait(chan, "vm-and");
06622 }
06623 if (!res && vms->oldmessages) {
06624 num = div(vms->oldmessages, 10);
06625 if (vms->oldmessages == 1) {
06626 res = ast_play_and_wait(chan, "digits/1-a");
06627 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
06628 res = res ? res : ast_play_and_wait(chan, "vm-message");
06629 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06630 if (num.rem == 2) {
06631 if (!num.quot) {
06632 res = ast_play_and_wait(chan, "digits/2-ie");
06633 } else {
06634 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
06635 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06636 }
06637 } else {
06638 res = say_and_wait(chan, vms->oldmessages, chan->language);
06639 }
06640 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
06641 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06642 } else {
06643 res = say_and_wait(chan, vms->oldmessages, chan->language);
06644 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
06645 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06646 }
06647 }
06648
06649 return res;
06650 }
06651
06652
06653 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
06654 {
06655
06656 int res;
06657
06658 res = ast_play_and_wait(chan, "vm-youhave");
06659 if (res)
06660 return res;
06661
06662 if (!vms->oldmessages && !vms->newmessages) {
06663 res = ast_play_and_wait(chan, "vm-no");
06664 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06665 return res;
06666 }
06667
06668 if (vms->newmessages) {
06669 if ((vms->newmessages == 1)) {
06670 res = ast_play_and_wait(chan, "digits/ett");
06671 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
06672 res = res ? res : ast_play_and_wait(chan, "vm-message");
06673 } else {
06674 res = say_and_wait(chan, vms->newmessages, chan->language);
06675 res = res ? res : ast_play_and_wait(chan, "vm-nya");
06676 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06677 }
06678 if (!res && vms->oldmessages)
06679 res = ast_play_and_wait(chan, "vm-and");
06680 }
06681 if (!res && vms->oldmessages) {
06682 if (vms->oldmessages == 1) {
06683 res = ast_play_and_wait(chan, "digits/ett");
06684 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
06685 res = res ? res : ast_play_and_wait(chan, "vm-message");
06686 } else {
06687 res = say_and_wait(chan, vms->oldmessages, chan->language);
06688 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
06689 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06690 }
06691 }
06692
06693 return res;
06694 }
06695
06696
06697 static int vm_intro_no(struct ast_channel *chan,struct vm_state *vms)
06698 {
06699
06700 int res;
06701
06702 res = ast_play_and_wait(chan, "vm-youhave");
06703 if (res)
06704 return res;
06705
06706 if (!vms->oldmessages && !vms->newmessages) {
06707 res = ast_play_and_wait(chan, "vm-no");
06708 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06709 return res;
06710 }
06711
06712 if (vms->newmessages) {
06713 if ((vms->newmessages == 1)) {
06714 res = ast_play_and_wait(chan, "digits/1");
06715 res = res ? res : ast_play_and_wait(chan, "vm-ny");
06716 res = res ? res : ast_play_and_wait(chan, "vm-message");
06717 } else {
06718 res = say_and_wait(chan, vms->newmessages, chan->language);
06719 res = res ? res : ast_play_and_wait(chan, "vm-nye");
06720 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06721 }
06722 if (!res && vms->oldmessages)
06723 res = ast_play_and_wait(chan, "vm-and");
06724 }
06725 if (!res && vms->oldmessages) {
06726 if (vms->oldmessages == 1) {
06727 res = ast_play_and_wait(chan, "digits/1");
06728 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
06729 res = res ? res : ast_play_and_wait(chan, "vm-message");
06730 } else {
06731 res = say_and_wait(chan, vms->oldmessages, chan->language);
06732 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
06733 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06734 }
06735 }
06736
06737 return res;
06738 }
06739
06740
06741 static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
06742 {
06743
06744 int res;
06745 res = ast_play_and_wait(chan, "vm-youhave");
06746 if (!res) {
06747 if (vms->newmessages) {
06748 if ((vms->newmessages == 1))
06749 res = ast_play_and_wait(chan, "digits/1F");
06750 else
06751 res = say_and_wait(chan, vms->newmessages, chan->language);
06752 if (!res)
06753 res = ast_play_and_wait(chan, "vm-INBOX");
06754 if (vms->oldmessages && !res)
06755 res = ast_play_and_wait(chan, "vm-and");
06756 else if (!res) {
06757 if ((vms->newmessages == 1))
06758 res = ast_play_and_wait(chan, "vm-message");
06759 else
06760 res = ast_play_and_wait(chan, "vm-messages");
06761 }
06762
06763 }
06764 if (!res && vms->oldmessages) {
06765 if (vms->oldmessages == 1)
06766 res = ast_play_and_wait(chan, "digits/1F");
06767 else
06768 res = say_and_wait(chan, vms->oldmessages, chan->language);
06769 if (!res)
06770 res = ast_play_and_wait(chan, "vm-Old");
06771 if (!res) {
06772 if (vms->oldmessages == 1)
06773 res = ast_play_and_wait(chan, "vm-message");
06774 else
06775 res = ast_play_and_wait(chan, "vm-messages");
06776 }
06777 }
06778 if (!res) {
06779 if (!vms->oldmessages && !vms->newmessages) {
06780 res = ast_play_and_wait(chan, "vm-no");
06781 if (!res)
06782 res = ast_play_and_wait(chan, "vm-messages");
06783 }
06784 }
06785 }
06786 return res;
06787 }
06788
06789
06790 static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
06791 {
06792
06793 int res;
06794 if (!vms->oldmessages && !vms->newmessages) {
06795 res = ast_play_and_wait(chan, "vm-youhaveno");
06796 if (!res)
06797 res = ast_play_and_wait(chan, "vm-messages");
06798 } else {
06799 res = ast_play_and_wait(chan, "vm-youhave");
06800 }
06801 if (!res) {
06802 if (vms->newmessages) {
06803 if (!res) {
06804 if ((vms->newmessages == 1)) {
06805 res = ast_play_and_wait(chan, "digits/1");
06806 if (!res)
06807 res = ast_play_and_wait(chan, "vm-message");
06808 if (!res)
06809 res = ast_play_and_wait(chan, "vm-INBOXs");
06810 } else {
06811 res = say_and_wait(chan, vms->newmessages, chan->language);
06812 if (!res)
06813 res = ast_play_and_wait(chan, "vm-messages");
06814 if (!res)
06815 res = ast_play_and_wait(chan, "vm-INBOX");
06816 }
06817 }
06818 if (vms->oldmessages && !res)
06819 res = ast_play_and_wait(chan, "vm-and");
06820 }
06821 if (vms->oldmessages) {
06822 if (!res) {
06823 if (vms->oldmessages == 1) {
06824 res = ast_play_and_wait(chan, "digits/1");
06825 if (!res)
06826 res = ast_play_and_wait(chan, "vm-message");
06827 if (!res)
06828 res = ast_play_and_wait(chan, "vm-Olds");
06829 } else {
06830 res = say_and_wait(chan, vms->oldmessages, chan->language);
06831 if (!res)
06832 res = ast_play_and_wait(chan, "vm-messages");
06833 if (!res)
06834 res = ast_play_and_wait(chan, "vm-Old");
06835 }
06836 }
06837 }
06838 }
06839 return res;
06840 }
06841
06842
06843 static int vm_intro_pt_BR(struct ast_channel *chan,struct vm_state *vms) {
06844
06845 int res;
06846 if (!vms->oldmessages && !vms->newmessages) {
06847 res = ast_play_and_wait(chan, "vm-nomessages");
06848 return res;
06849 }
06850 else {
06851 res = ast_play_and_wait(chan, "vm-youhave");
06852 }
06853 if (vms->newmessages) {
06854 if (!res)
06855 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06856 if ((vms->newmessages == 1)) {
06857 if (!res)
06858 res = ast_play_and_wait(chan, "vm-message");
06859 if (!res)
06860 res = ast_play_and_wait(chan, "vm-INBOXs");
06861 }
06862 else {
06863 if (!res)
06864 res = ast_play_and_wait(chan, "vm-messages");
06865 if (!res)
06866 res = ast_play_and_wait(chan, "vm-INBOX");
06867 }
06868 if (vms->oldmessages && !res)
06869 res = ast_play_and_wait(chan, "vm-and");
06870 }
06871 if (vms->oldmessages) {
06872 if (!res)
06873 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06874 if (vms->oldmessages == 1) {
06875 if (!res)
06876 res = ast_play_and_wait(chan, "vm-message");
06877 if (!res)
06878 res = ast_play_and_wait(chan, "vm-Olds");
06879 }
06880 else {
06881 if (!res)
06882 res = ast_play_and_wait(chan, "vm-messages");
06883 if (!res)
06884 res = ast_play_and_wait(chan, "vm-Old");
06885 }
06886 }
06887 return res;
06888 }
06889
06890
06891 static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
06892 {
06893
06894 int res;
06895 res = ast_play_and_wait(chan, "vm-youhave");
06896 if (!res) {
06897 if (vms->newmessages) {
06898 res = say_and_wait(chan, vms->newmessages, chan->language);
06899 if (!res)
06900 res = ast_play_and_wait(chan, "vm-INBOX");
06901 if (vms->oldmessages && !res)
06902 res = ast_play_and_wait(chan, "vm-and");
06903 else if (!res) {
06904 if ((vms->newmessages == 1))
06905 res = ast_play_and_wait(chan, "vm-message");
06906 else
06907 res = ast_play_and_wait(chan, "vm-messages");
06908 }
06909
06910 }
06911 if (!res && vms->oldmessages) {
06912 res = say_and_wait(chan, vms->oldmessages, chan->language);
06913 if (!res)
06914 res = ast_play_and_wait(chan, "vm-Old");
06915 if (!res) {
06916 if (vms->oldmessages == 1)
06917 res = ast_play_and_wait(chan, "vm-message");
06918 else
06919 res = ast_play_and_wait(chan, "vm-messages");
06920 }
06921 }
06922 if (!res) {
06923 if (!vms->oldmessages && !vms->newmessages) {
06924 res = ast_play_and_wait(chan, "vm-no");
06925 if (!res)
06926 res = ast_play_and_wait(chan, "vm-messages");
06927 }
06928 }
06929 }
06930 return res;
06931 }
06932
06933
06934 static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
06935 {
06936
06937 int res;
06938 res = ast_play_and_wait(chan, "vm-youhave");
06939 if (!res) {
06940 if (vms->newmessages) {
06941 res = say_and_wait(chan, vms->newmessages, chan->language);
06942 if (!res) {
06943 if (vms->newmessages == 1)
06944 res = ast_play_and_wait(chan, "vm-INBOXs");
06945 else
06946 res = ast_play_and_wait(chan, "vm-INBOX");
06947 }
06948 if (vms->oldmessages && !res)
06949 res = ast_play_and_wait(chan, "vm-and");
06950 else if (!res) {
06951 if ((vms->newmessages == 1))
06952 res = ast_play_and_wait(chan, "vm-message");
06953 else
06954 res = ast_play_and_wait(chan, "vm-messages");
06955 }
06956
06957 }
06958 if (!res && vms->oldmessages) {
06959 res = say_and_wait(chan, vms->oldmessages, chan->language);
06960 if (!res) {
06961 if (vms->oldmessages == 1)
06962 res = ast_play_and_wait(chan, "vm-Olds");
06963 else
06964 res = ast_play_and_wait(chan, "vm-Old");
06965 }
06966 if (!res) {
06967 if (vms->oldmessages == 1)
06968 res = ast_play_and_wait(chan, "vm-message");
06969 else
06970 res = ast_play_and_wait(chan, "vm-messages");
06971 }
06972 }
06973 if (!res) {
06974 if (!vms->oldmessages && !vms->newmessages) {
06975 res = ast_play_and_wait(chan, "vm-no");
06976 if (!res)
06977 res = ast_play_and_wait(chan, "vm-messages");
06978 }
06979 }
06980 }
06981 return res;
06982 }
06983
06984
06985 static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
06986 {
06987
06988 int res;
06989 res = ast_play_and_wait(chan, "vm-youhave");
06990 if (!res) {
06991 if (vms->newmessages) {
06992 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06993 if (!res) {
06994 if ((vms->newmessages == 1)) {
06995 res = ast_play_and_wait(chan, "vm-message");
06996 if (!res)
06997 res = ast_play_and_wait(chan, "vm-INBOXs");
06998 } else {
06999 res = ast_play_and_wait(chan, "vm-messages");
07000 if (!res)
07001 res = ast_play_and_wait(chan, "vm-INBOX");
07002 }
07003 }
07004 if (vms->oldmessages && !res)
07005 res = ast_play_and_wait(chan, "vm-and");
07006 }
07007 if (!res && vms->oldmessages) {
07008 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07009 if (!res) {
07010 if (vms->oldmessages == 1) {
07011 res = ast_play_and_wait(chan, "vm-message");
07012 if (!res)
07013 res = ast_play_and_wait(chan, "vm-Olds");
07014 } else {
07015 res = ast_play_and_wait(chan, "vm-messages");
07016 if (!res)
07017 res = ast_play_and_wait(chan, "vm-Old");
07018 }
07019 }
07020 }
07021 if (!res) {
07022 if (!vms->oldmessages && !vms->newmessages) {
07023 res = ast_play_and_wait(chan, "vm-no");
07024 if (!res)
07025 res = ast_play_and_wait(chan, "vm-messages");
07026 }
07027 }
07028 }
07029 return res;
07030 }
07031
07032
07033
07034
07035
07036
07037
07038
07039
07040
07041
07042
07043
07044
07045
07046
07047
07048 static int vm_intro_cs(struct ast_channel *chan,struct vm_state *vms)
07049 {
07050 int res;
07051 res = ast_play_and_wait(chan, "vm-youhave");
07052 if (!res) {
07053 if (vms->newmessages) {
07054 if (vms->newmessages == 1) {
07055 res = ast_play_and_wait(chan, "digits/jednu");
07056 } else {
07057 res = say_and_wait(chan, vms->newmessages, chan->language);
07058 }
07059 if (!res) {
07060 if ((vms->newmessages == 1))
07061 res = ast_play_and_wait(chan, "vm-novou");
07062 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
07063 res = ast_play_and_wait(chan, "vm-nove");
07064 if (vms->newmessages > 4)
07065 res = ast_play_and_wait(chan, "vm-novych");
07066 }
07067 if (vms->oldmessages && !res)
07068 res = ast_play_and_wait(chan, "vm-and");
07069 else if (!res) {
07070 if ((vms->newmessages == 1))
07071 res = ast_play_and_wait(chan, "vm-zpravu");
07072 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
07073 res = ast_play_and_wait(chan, "vm-zpravy");
07074 if (vms->newmessages > 4)
07075 res = ast_play_and_wait(chan, "vm-zprav");
07076 }
07077 }
07078 if (!res && vms->oldmessages) {
07079 res = say_and_wait(chan, vms->oldmessages, chan->language);
07080 if (!res) {
07081 if ((vms->oldmessages == 1))
07082 res = ast_play_and_wait(chan, "vm-starou");
07083 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
07084 res = ast_play_and_wait(chan, "vm-stare");
07085 if (vms->oldmessages > 4)
07086 res = ast_play_and_wait(chan, "vm-starych");
07087 }
07088 if (!res) {
07089 if ((vms->oldmessages == 1))
07090 res = ast_play_and_wait(chan, "vm-zpravu");
07091 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
07092 res = ast_play_and_wait(chan, "vm-zpravy");
07093 if (vms->oldmessages > 4)
07094 res = ast_play_and_wait(chan, "vm-zprav");
07095 }
07096 }
07097 if (!res) {
07098 if (!vms->oldmessages && !vms->newmessages) {
07099 res = ast_play_and_wait(chan, "vm-no");
07100 if (!res)
07101 res = ast_play_and_wait(chan, "vm-zpravy");
07102 }
07103 }
07104 }
07105 return res;
07106 }
07107
07108 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07109 {
07110 char prefile[256];
07111
07112
07113 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07114 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
07115 RETRIEVE(prefile, -1, vmu);
07116 if (ast_fileexists(prefile, NULL, NULL) > 0)
07117 ast_play_and_wait(chan, "vm-tempgreetactive");
07118 DISPOSE(prefile, -1);
07119 }
07120
07121
07122 if (0) {
07123 return 0;
07124 } else if (!strncasecmp(chan->language, "cs", 2)) {
07125 return vm_intro_cs(chan, vms);
07126 } else if (!strncasecmp(chan->language, "cz", 2)) {
07127 static int deprecation_warning = 0;
07128 if (deprecation_warning++ % 10 == 0) {
07129 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
07130 }
07131 return vm_intro_cs(chan, vms);
07132 } else if (!strncasecmp(chan->language, "de", 2)) {
07133 return vm_intro_de(chan, vms);
07134 } else if (!strncasecmp(chan->language, "es", 2)) {
07135 return vm_intro_es(chan, vms);
07136 } else if (!strncasecmp(chan->language, "fr", 2)) {
07137 return vm_intro_fr(chan, vms);
07138 } else if (!strncasecmp(chan->language, "gr", 2)) {
07139 return vm_intro_gr(chan, vms);
07140 } else if (!strncasecmp(chan->language, "he", 2)) {
07141 return vm_intro_he(chan, vms);
07142 } else if (!strncasecmp(chan->language, "it", 2)) {
07143 return vm_intro_it(chan, vms);
07144 } else if (!strncasecmp(chan->language, "nl", 2)) {
07145 return vm_intro_nl(chan, vms);
07146 } else if (!strncasecmp(chan->language, "no", 2)) {
07147 return vm_intro_no(chan, vms);
07148 } else if (!strncasecmp(chan->language, "pl", 2)) {
07149 return vm_intro_pl(chan, vms);
07150 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07151 return vm_intro_pt_BR(chan, vms);
07152 } else if (!strncasecmp(chan->language, "pt", 2)) {
07153 return vm_intro_pt(chan, vms);
07154 } else if (!strncasecmp(chan->language, "ru", 2)) {
07155 return vm_intro_multilang(chan, vms, "n");
07156 } else if (!strncasecmp(chan->language, "se", 2)) {
07157 return vm_intro_se(chan, vms);
07158 } else if (!strncasecmp(chan->language, "ua", 2)) {
07159 return vm_intro_multilang(chan, vms, "n");
07160 } else {
07161 return vm_intro_en(chan, vms);
07162 }
07163 }
07164
07165 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
07166 {
07167 int res = 0;
07168
07169 while (!res) {
07170 if (vms->starting) {
07171 if (vms->lastmsg > -1) {
07172 res = ast_play_and_wait(chan, "vm-onefor");
07173 if (!strncasecmp(chan->language, "he", 2)) {
07174 res = ast_play_and_wait(chan, "vm-for");
07175 }
07176 if (!res)
07177 res = vm_play_folder_name(chan, vms->vmbox);
07178 }
07179 if (!res)
07180 res = ast_play_and_wait(chan, "vm-opts");
07181 } else {
07182 if (vms->curmsg)
07183 res = ast_play_and_wait(chan, "vm-prev");
07184 if (!res && !skipadvanced)
07185 res = ast_play_and_wait(chan, "vm-advopts");
07186 if (!res)
07187 res = ast_play_and_wait(chan, "vm-repeat");
07188 if (!res && (vms->curmsg != vms->lastmsg))
07189 res = ast_play_and_wait(chan, "vm-next");
07190 if (!res) {
07191 if (!vms->deleted[vms->curmsg])
07192 res = ast_play_and_wait(chan, "vm-delete");
07193 else
07194 res = ast_play_and_wait(chan, "vm-undelete");
07195 if (!res)
07196 res = ast_play_and_wait(chan, "vm-toforward");
07197 if (!res)
07198 res = ast_play_and_wait(chan, "vm-savemessage");
07199 }
07200 }
07201 if (!res)
07202 res = ast_play_and_wait(chan, "vm-helpexit");
07203 if (!res)
07204 res = ast_waitfordigit(chan, 6000);
07205 if (!res) {
07206 vms->repeats++;
07207 if (vms->repeats > 2) {
07208 res = 't';
07209 }
07210 }
07211 }
07212 return res;
07213 }
07214
07215 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07216 {
07217 int cmd = 0;
07218 int duration = 0;
07219 int tries = 0;
07220 char newpassword[80] = "";
07221 char newpassword2[80] = "";
07222 char prefile[PATH_MAX] = "";
07223 unsigned char buf[256];
07224 int bytes=0;
07225
07226 if (ast_adsi_available(chan)) {
07227 bytes += adsi_logo(buf + bytes);
07228 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
07229 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07230 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07231 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07232 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07233 }
07234
07235
07236
07237 for (;;) {
07238 newpassword[1] = '\0';
07239 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
07240 if (cmd == '#')
07241 newpassword[0] = '\0';
07242 if (cmd < 0 || cmd == 't' || cmd == '#')
07243 return cmd;
07244 cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#");
07245 if (cmd < 0 || cmd == 't' || cmd == '#')
07246 return cmd;
07247 newpassword2[1] = '\0';
07248 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
07249 if (cmd == '#')
07250 newpassword2[0] = '\0';
07251 if (cmd < 0 || cmd == 't' || cmd == '#')
07252 return cmd;
07253 cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#");
07254 if (cmd < 0 || cmd == 't' || cmd == '#')
07255 return cmd;
07256 if (!strcmp(newpassword, newpassword2))
07257 break;
07258 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
07259 cmd = ast_play_and_wait(chan, "vm-mismatch");
07260 if (++tries == 3)
07261 return -1;
07262 if (cmd == 0) {
07263 cmd = ast_play_and_wait(chan, "vm-pls-try-again");
07264 }
07265 }
07266 if (ast_strlen_zero(ext_pass_cmd))
07267 vm_change_password(vmu,newpassword);
07268 else
07269 vm_change_password_shell(vmu,newpassword);
07270 if (option_debug > 2)
07271 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
07272 cmd = ast_play_and_wait(chan,"vm-passchanged");
07273
07274
07275 if (ast_test_flag(vmu, VM_FORCENAME)) {
07276 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
07277 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07278 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07279 if (cmd < 0 || cmd == 't' || cmd == '#')
07280 return cmd;
07281 }
07282 }
07283
07284
07285 if (ast_test_flag(vmu, VM_FORCEGREET)) {
07286 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
07287 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07288 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07289 if (cmd < 0 || cmd == 't' || cmd == '#')
07290 return cmd;
07291 }
07292
07293 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
07294 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07295 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07296 if (cmd < 0 || cmd == 't' || cmd == '#')
07297 return cmd;
07298 }
07299 }
07300
07301 return cmd;
07302 }
07303
07304 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07305 {
07306 int cmd = 0;
07307 int retries = 0;
07308 int duration = 0;
07309 char newpassword[80] = "";
07310 char newpassword2[80] = "";
07311 char prefile[PATH_MAX] = "";
07312 unsigned char buf[256];
07313 int bytes=0;
07314
07315 if (ast_adsi_available(chan))
07316 {
07317 bytes += adsi_logo(buf + bytes);
07318 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
07319 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07320 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07321 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07322 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07323 }
07324 while ((cmd >= 0) && (cmd != 't')) {
07325 if (cmd)
07326 retries = 0;
07327 switch (cmd) {
07328 case '1':
07329 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
07330 cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07331 break;
07332 case '2':
07333 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
07334 cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07335 break;
07336 case '3':
07337 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
07338 cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07339 break;
07340 case '4':
07341 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
07342 break;
07343 case '5':
07344 if (vmu->password[0] == '-') {
07345 cmd = ast_play_and_wait(chan, "vm-no");
07346 break;
07347 }
07348 newpassword[1] = '\0';
07349 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
07350 if (cmd == '#')
07351 newpassword[0] = '\0';
07352 else {
07353 if (cmd < 0)
07354 break;
07355 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
07356 break;
07357 }
07358 }
07359 newpassword2[1] = '\0';
07360 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
07361 if (cmd == '#')
07362 newpassword2[0] = '\0';
07363 else {
07364 if (cmd < 0)
07365 break;
07366
07367 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#")) < 0) {
07368 break;
07369 }
07370 }
07371 if (strcmp(newpassword, newpassword2)) {
07372 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
07373 cmd = ast_play_and_wait(chan, "vm-mismatch");
07374 if (!cmd) {
07375 cmd = ast_play_and_wait(chan, "vm-pls-try-again");
07376 }
07377 break;
07378 }
07379 if (ast_strlen_zero(ext_pass_cmd))
07380 vm_change_password(vmu,newpassword);
07381 else
07382 vm_change_password_shell(vmu,newpassword);
07383 if (option_debug > 2)
07384 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
07385 cmd = ast_play_and_wait(chan,"vm-passchanged");
07386 break;
07387 case '*':
07388 cmd = 't';
07389 break;
07390 default:
07391 cmd = 0;
07392 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07393 RETRIEVE(prefile, -1, vmu);
07394 if (ast_fileexists(prefile, NULL, NULL))
07395 cmd = ast_play_and_wait(chan, "vm-tmpexists");
07396 DISPOSE(prefile, -1);
07397 if (!cmd)
07398 cmd = ast_play_and_wait(chan, "vm-options");
07399 if (!cmd)
07400 cmd = ast_waitfordigit(chan,6000);
07401 if (!cmd)
07402 retries++;
07403 if (retries > 3)
07404 cmd = 't';
07405 }
07406 }
07407 if (cmd == 't')
07408 cmd = 0;
07409 return cmd;
07410 }
07411
07412 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07413 {
07414 int res;
07415 int cmd = 0;
07416 int retries = 0;
07417 int duration = 0;
07418 char prefile[PATH_MAX] = "";
07419 unsigned char buf[256];
07420 char dest[PATH_MAX];
07421 int bytes = 0;
07422
07423 if (ast_adsi_available(chan)) {
07424 bytes += adsi_logo(buf + bytes);
07425 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
07426 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07427 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07428 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07429 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07430 }
07431
07432 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07433 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, vms->username, "temp"))) {
07434 ast_log(LOG_WARNING, "Failed to create directory (%s).\n", prefile);
07435 return -1;
07436 }
07437 while ((cmd >= 0) && (cmd != 't')) {
07438 if (cmd)
07439 retries = 0;
07440 RETRIEVE(prefile, -1, vmu);
07441 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
07442 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07443 cmd = 't';
07444 } else {
07445 switch (cmd) {
07446 case '1':
07447 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07448 break;
07449 case '2':
07450 DELETE(prefile, -1, prefile, vmu);
07451 ast_play_and_wait(chan, "vm-tempremoved");
07452 cmd = 't';
07453 break;
07454 case '*':
07455 cmd = 't';
07456 break;
07457 default:
07458 cmd = ast_play_and_wait(chan,
07459 ast_fileexists(prefile, NULL, NULL) > 0 ?
07460 "vm-tempgreeting2" : "vm-tempgreeting");
07461 if (!cmd)
07462 cmd = ast_waitfordigit(chan,6000);
07463 if (!cmd)
07464 retries++;
07465 if (retries > 3)
07466 cmd = 't';
07467 }
07468 }
07469 DISPOSE(prefile, -1);
07470 }
07471 if (cmd == 't')
07472 cmd = 0;
07473 return cmd;
07474 }
07475
07476
07477 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07478 {
07479 int cmd=0;
07480
07481 if (vms->lastmsg > -1) {
07482 cmd = play_message(chan, vmu, vms);
07483 } else {
07484 cmd = ast_play_and_wait(chan, "vm-youhave");
07485 if (!cmd)
07486 cmd = ast_play_and_wait(chan, "vm-no");
07487 if (!cmd) {
07488 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07489 cmd = ast_play_and_wait(chan, vms->fn);
07490 }
07491 if (!cmd)
07492 cmd = ast_play_and_wait(chan, "vm-messages");
07493 }
07494 return cmd;
07495 }
07496
07497
07498 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07499 {
07500 int cmd = 0;
07501
07502 if (vms->lastmsg > -1) {
07503 cmd = play_message(chan, vmu, vms);
07504 } else {
07505 if (!strcasecmp(vms->fn, "INBOX")) {
07506 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
07507 } else {
07508 cmd = ast_play_and_wait(chan, "vm-nomessages");
07509 }
07510 }
07511 return cmd;
07512 }
07513
07514
07515 static int vm_browse_messages_latin(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07516 {
07517 int cmd=0;
07518
07519 if (vms->lastmsg > -1) {
07520 cmd = play_message(chan, vmu, vms);
07521 } else {
07522 cmd = ast_play_and_wait(chan, "vm-youhaveno");
07523 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
07524 if (!cmd) {
07525 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
07526 cmd = ast_play_and_wait(chan, vms->fn);
07527 }
07528 if (!cmd)
07529 cmd = ast_play_and_wait(chan, "vm-messages");
07530 } else {
07531 if (!cmd)
07532 cmd = ast_play_and_wait(chan, "vm-messages");
07533 if (!cmd) {
07534 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07535 cmd = ast_play_and_wait(chan, vms->fn);
07536 }
07537 }
07538 }
07539 return cmd;
07540 }
07541
07542 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07543 {
07544 if (!strncasecmp(chan->language, "es", 2) ||
07545 !strncasecmp(chan->language, "it", 2) ||
07546 !strncasecmp(chan->language, "pt", 2) ||
07547 !strncasecmp(chan->language, "gr", 2)) {
07548 return vm_browse_messages_latin(chan, vms, vmu);
07549 } else if (!strncasecmp(chan->language, "he", 2)) {
07550 return vm_browse_messages_he(chan, vms, vmu);
07551 } else {
07552 return vm_browse_messages_en(chan, vms, vmu);
07553 }
07554 }
07555
07556 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
07557 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
07558 int skipuser, int maxlogins, int silent)
07559 {
07560 int useadsi=0, valid=0, logretries=0;
07561 char password[AST_MAX_EXTENSION]="", *passptr;
07562 struct ast_vm_user vmus, *vmu = NULL;
07563
07564
07565 adsi_begin(chan, &useadsi);
07566 if (!skipuser && useadsi)
07567 adsi_login(chan);
07568 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
07569 ast_log(LOG_WARNING, "Couldn't stream login file\n");
07570 return -1;
07571 }
07572
07573
07574
07575 while (!valid && (logretries < maxlogins)) {
07576
07577 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
07578 ast_log(LOG_WARNING, "Couldn't read username\n");
07579 return -1;
07580 }
07581 if (ast_strlen_zero(mailbox)) {
07582 if (chan->cid.cid_num) {
07583 ast_copy_string(mailbox, chan->cid.cid_num, mailbox_size);
07584 } else {
07585 if (option_verbose > 2)
07586 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
07587 return -1;
07588 }
07589 }
07590 if (useadsi)
07591 adsi_password(chan);
07592
07593 if (!ast_strlen_zero(prefix)) {
07594 char fullusername[80] = "";
07595 ast_copy_string(fullusername, prefix, sizeof(fullusername));
07596 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
07597 ast_copy_string(mailbox, fullusername, mailbox_size);
07598 }
07599
07600 if (option_debug)
07601 ast_log(LOG_DEBUG, "Before find user for mailbox %s\n",mailbox);
07602 vmu = find_user(&vmus, context, mailbox);
07603 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
07604
07605 password[0] = '\0';
07606 } else {
07607 if (ast_streamfile(chan, "vm-password", chan->language)) {
07608 ast_log(LOG_WARNING, "Unable to stream password file\n");
07609 return -1;
07610 }
07611 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
07612 ast_log(LOG_WARNING, "Unable to read password\n");
07613 return -1;
07614 }
07615 }
07616
07617 if (vmu) {
07618 passptr = vmu->password;
07619 if (passptr[0] == '-') passptr++;
07620 }
07621 if (vmu && !strcmp(passptr, password))
07622 valid++;
07623 else {
07624 if (option_verbose > 2)
07625 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
07626 if (!ast_strlen_zero(prefix))
07627 mailbox[0] = '\0';
07628 }
07629 logretries++;
07630 if (!valid) {
07631 if (skipuser || logretries >= maxlogins) {
07632 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
07633 ast_log(LOG_WARNING, "Unable to stream incorrect message\n");
07634 return -1;
07635 }
07636 } else {
07637 if (useadsi)
07638 adsi_login(chan);
07639 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
07640 ast_log(LOG_WARNING, "Unable to stream incorrect mailbox message\n");
07641 return -1;
07642 }
07643 }
07644 if (ast_waitstream(chan, ""))
07645 return -1;
07646 }
07647 }
07648 if (!valid && (logretries >= maxlogins)) {
07649 ast_stopstream(chan);
07650 ast_play_and_wait(chan, "vm-goodbye");
07651 return -1;
07652 }
07653 if (vmu && !skipuser) {
07654 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
07655 }
07656 return 0;
07657 }
07658
07659 static int vm_execmain(struct ast_channel *chan, void *data)
07660 {
07661
07662
07663
07664 int res=-1;
07665 int cmd=0;
07666 int valid = 0;
07667 struct ast_module_user *u;
07668 char prefixstr[80] ="";
07669 char ext_context[256]="";
07670 int box;
07671 int useadsi = 0;
07672 int skipuser = 0;
07673 struct vm_state vms;
07674 struct ast_vm_user *vmu = NULL, vmus;
07675 char *context=NULL;
07676 int silentexit = 0;
07677 struct ast_flags flags = { 0 };
07678 signed char record_gain = 0;
07679 int play_auto = 0;
07680 int play_folder = 0;
07681 #ifdef IMAP_STORAGE
07682 int deleted = 0;
07683 #endif
07684 u = ast_module_user_add(chan);
07685
07686
07687 memset(&vms, 0, sizeof(vms));
07688 vms.lastmsg = -1;
07689
07690 memset(&vmus, 0, sizeof(vmus));
07691
07692 if (chan->_state != AST_STATE_UP) {
07693 if (option_debug)
07694 ast_log(LOG_DEBUG, "Before ast_answer\n");
07695 ast_answer(chan);
07696 }
07697
07698 if (!ast_strlen_zero(data)) {
07699 char *opts[OPT_ARG_ARRAY_SIZE];
07700 char *parse;
07701 AST_DECLARE_APP_ARGS(args,
07702 AST_APP_ARG(argv0);
07703 AST_APP_ARG(argv1);
07704 );
07705
07706 parse = ast_strdupa(data);
07707
07708 AST_STANDARD_APP_ARGS(args, parse);
07709
07710 if (args.argc == 2) {
07711 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
07712 ast_module_user_remove(u);
07713 return -1;
07714 }
07715 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
07716 int gain;
07717 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
07718 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
07719 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
07720 ast_module_user_remove(u);
07721 return -1;
07722 } else {
07723 record_gain = (signed char) gain;
07724 }
07725 } else {
07726 ast_log(LOG_WARNING, "Invalid Gain level set with option g\n");
07727 }
07728 }
07729 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
07730 play_auto = 1;
07731 if (opts[OPT_ARG_PLAYFOLDER]) {
07732 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
07733 ast_log(LOG_WARNING, "Invalid value '%s' provided for folder autoplay option\n", opts[OPT_ARG_PLAYFOLDER]);
07734 }
07735 } else {
07736 ast_log(LOG_WARNING, "Invalid folder set with option a\n");
07737 }
07738 if ( play_folder > 9 || play_folder < 0) {
07739 ast_log(LOG_WARNING, "Invalid value '%d' provided for folder autoplay option\n", play_folder);
07740 play_folder = 0;
07741 }
07742 }
07743 } else {
07744
07745 while (*(args.argv0)) {
07746 if (*(args.argv0) == 's')
07747 ast_set_flag(&flags, OPT_SILENT);
07748 else if (*(args.argv0) == 'p')
07749 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
07750 else
07751 break;
07752 (args.argv0)++;
07753 }
07754
07755 }
07756
07757 valid = ast_test_flag(&flags, OPT_SILENT);
07758
07759 if ((context = strchr(args.argv0, '@')))
07760 *context++ = '\0';
07761
07762 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
07763 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
07764 else
07765 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
07766
07767 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
07768 skipuser++;
07769 else
07770 valid = 0;
07771 }
07772
07773 if (!valid)
07774 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
07775
07776 if (option_debug)
07777 ast_log(LOG_DEBUG, "After vm_authenticate\n");
07778 if (!res) {
07779 valid = 1;
07780 if (!skipuser)
07781 vmu = &vmus;
07782 } else {
07783 res = 0;
07784 }
07785
07786
07787 adsi_begin(chan, &useadsi);
07788
07789 if (!valid) {
07790 goto out;
07791 }
07792
07793 #ifdef IMAP_STORAGE
07794 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
07795 pthread_setspecific(ts_vmstate.key, &vms);
07796
07797 vms.interactive = 1;
07798 vms.updated = 1;
07799 if (vmu)
07800 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
07801 vmstate_insert(&vms);
07802 init_vm_state(&vms);
07803 #endif
07804
07805
07806 if (!ast_strlen_zero(vmu->language))
07807 ast_string_field_set(chan, language, vmu->language);
07808 create_dirpath(vms.curdir, sizeof(vms.curdir), vmu->context, vms.username, "");
07809
07810 if (option_debug)
07811 ast_log(LOG_DEBUG, "Before open_mailbox\n");
07812 res = open_mailbox(&vms, vmu, 1);
07813 if (res < 0)
07814 goto out;
07815 vms.oldmessages = vms.lastmsg + 1;
07816 if (option_debug > 2)
07817 ast_log(LOG_DEBUG, "Number of old messages: %d\n",vms.oldmessages);
07818
07819 res = open_mailbox(&vms, vmu, 0);
07820 if (res < 0)
07821 goto out;
07822 vms.newmessages = vms.lastmsg + 1;
07823 if (option_debug > 2)
07824 ast_log(LOG_DEBUG, "Number of new messages: %d\n",vms.newmessages);
07825
07826
07827 if (play_auto) {
07828 res = open_mailbox(&vms, vmu, play_folder);
07829 if (res < 0)
07830 goto out;
07831
07832
07833 if (vms.lastmsg == -1) {
07834 cmd = vm_browse_messages(chan, &vms, vmu);
07835 res = 0;
07836 goto out;
07837 }
07838 } else {
07839 if (!vms.newmessages && vms.oldmessages) {
07840
07841 res = open_mailbox(&vms, vmu, 1);
07842 play_folder = 1;
07843 if (res < 0)
07844 goto out;
07845 }
07846 }
07847
07848 if (useadsi)
07849 adsi_status(chan, &vms);
07850 res = 0;
07851
07852
07853 if (!strcasecmp(vmu->mailbox, vmu->password) &&
07854 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
07855 if (ast_play_and_wait(chan, "vm-newuser") == -1)
07856 ast_log(LOG_WARNING, "Couldn't stream new user file\n");
07857 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
07858 if ((cmd == 't') || (cmd == '#')) {
07859
07860 res = 0;
07861 goto out;
07862 } else if (cmd < 0) {
07863
07864 res = -1;
07865 goto out;
07866 }
07867 }
07868 #ifdef IMAP_STORAGE
07869 if (option_debug > 2)
07870 ast_log(LOG_DEBUG, "Checking quotas: comparing %u to %u\n",vms.quota_usage,vms.quota_limit);
07871 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
07872 if (option_debug)
07873 ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!!\n");
07874 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
07875 }
07876 if (option_debug > 2)
07877 ast_log(LOG_DEBUG, "Checking quotas: User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
07878 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
07879 ast_log(LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
07880 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
07881 }
07882 #endif
07883 if (play_auto) {
07884 cmd = '1';
07885 } else {
07886 cmd = vm_intro(chan, vmu, &vms);
07887 }
07888
07889 vms.repeats = 0;
07890 vms.starting = 1;
07891 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
07892
07893 switch (cmd) {
07894 case '1':
07895 vms.curmsg = 0;
07896
07897 case '5':
07898 cmd = vm_browse_messages(chan, &vms, vmu);
07899 break;
07900 case '2':
07901 if (useadsi)
07902 adsi_folders(chan, 0, "Change to folder...");
07903 cmd = get_folder2(chan, "vm-changeto", 0);
07904 if (cmd == '#') {
07905 cmd = 0;
07906 } else if (cmd > 0) {
07907 cmd = cmd - '0';
07908 res = close_mailbox(&vms, vmu);
07909 if (res == ERROR_LOCK_PATH)
07910 goto out;
07911 res = open_mailbox(&vms, vmu, cmd);
07912 if (res < 0)
07913 goto out;
07914 play_folder = cmd;
07915 cmd = 0;
07916 }
07917 if (useadsi)
07918 adsi_status2(chan, &vms);
07919
07920 if (!cmd)
07921 cmd = vm_play_folder_name(chan, vms.vmbox);
07922
07923 vms.starting = 1;
07924 break;
07925 case '3':
07926 cmd = 0;
07927 vms.repeats = 0;
07928 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
07929 switch (cmd) {
07930 case '1':
07931 if (vms.lastmsg > -1 && !vms.starting) {
07932 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
07933 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
07934 res = cmd;
07935 goto out;
07936 }
07937 } else
07938 cmd = ast_play_and_wait(chan, "vm-sorry");
07939 cmd = 't';
07940 break;
07941 case '2':
07942 if (option_verbose > 2 && !vms.starting)
07943 ast_verbose( VERBOSE_PREFIX_3 "Callback Requested\n");
07944 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
07945 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
07946 if (cmd == 9) {
07947 silentexit = 1;
07948 goto out;
07949 } else if (cmd == ERROR_LOCK_PATH) {
07950 res = cmd;
07951 goto out;
07952 }
07953 }
07954 else
07955 cmd = ast_play_and_wait(chan, "vm-sorry");
07956 cmd = 't';
07957 break;
07958 case '3':
07959 if (vms.lastmsg > -1 && !vms.starting) {
07960 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
07961 if (cmd == ERROR_LOCK_PATH) {
07962 res = cmd;
07963 goto out;
07964 }
07965 } else
07966 cmd = ast_play_and_wait(chan, "vm-sorry");
07967 cmd = 't';
07968 break;
07969 case '4':
07970 if (!ast_strlen_zero(vmu->dialout)) {
07971 cmd = dialout(chan, vmu, NULL, vmu->dialout);
07972 if (cmd == 9) {
07973 silentexit = 1;
07974 goto out;
07975 }
07976 }
07977 else
07978 cmd = ast_play_and_wait(chan, "vm-sorry");
07979 cmd = 't';
07980 break;
07981
07982 case '5':
07983 if (ast_test_flag(vmu, VM_SVMAIL)) {
07984 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain);
07985 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
07986 res = cmd;
07987 goto out;
07988 }
07989 } else
07990 cmd = ast_play_and_wait(chan,"vm-sorry");
07991 cmd='t';
07992 break;
07993
07994 case '*':
07995 cmd = 't';
07996 break;
07997
07998 default:
07999 cmd = 0;
08000 if (!vms.starting) {
08001 cmd = ast_play_and_wait(chan, "vm-toreply");
08002 }
08003 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
08004 cmd = ast_play_and_wait(chan, "vm-tocallback");
08005 }
08006 if (!cmd && !vms.starting) {
08007 cmd = ast_play_and_wait(chan, "vm-tohearenv");
08008 }
08009 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
08010 cmd = ast_play_and_wait(chan, "vm-tomakecall");
08011 }
08012 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
08013 cmd=ast_play_and_wait(chan, "vm-leavemsg");
08014 if (!cmd)
08015 cmd = ast_play_and_wait(chan, "vm-starmain");
08016 if (!cmd)
08017 cmd = ast_waitfordigit(chan,6000);
08018 if (!cmd)
08019 vms.repeats++;
08020 if (vms.repeats > 3)
08021 cmd = 't';
08022 }
08023 }
08024 if (cmd == 't') {
08025 cmd = 0;
08026 vms.repeats = 0;
08027 }
08028 break;
08029 case '4':
08030 if (vms.curmsg > 0) {
08031 vms.curmsg--;
08032 cmd = play_message(chan, vmu, &vms);
08033 } else {
08034 cmd = ast_play_and_wait(chan, "vm-nomore");
08035 }
08036 break;
08037 case '6':
08038 if (vms.curmsg < vms.lastmsg) {
08039 vms.curmsg++;
08040 cmd = play_message(chan, vmu, &vms);
08041 } else {
08042 cmd = ast_play_and_wait(chan, "vm-nomore");
08043 }
08044 break;
08045 case '7':
08046 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
08047 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
08048 if (useadsi)
08049 adsi_delete(chan, &vms);
08050 if (vms.deleted[vms.curmsg]) {
08051 if (play_folder == 0)
08052 vms.newmessages--;
08053 else if (play_folder == 1)
08054 vms.oldmessages--;
08055 cmd = ast_play_and_wait(chan, "vm-deleted");
08056 }
08057 else {
08058 if (play_folder == 0)
08059 vms.newmessages++;
08060 else if (play_folder == 1)
08061 vms.oldmessages++;
08062 cmd = ast_play_and_wait(chan, "vm-undeleted");
08063 }
08064 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
08065 if (vms.curmsg < vms.lastmsg) {
08066 vms.curmsg++;
08067 cmd = play_message(chan, vmu, &vms);
08068 } else {
08069 cmd = ast_play_and_wait(chan, "vm-nomore");
08070 }
08071 }
08072 } else
08073 cmd = 0;
08074 #ifdef IMAP_STORAGE
08075 deleted = 1;
08076 #endif
08077 break;
08078
08079 case '8':
08080 if (vms.lastmsg > -1) {
08081 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain);
08082 if (cmd == ERROR_LOCK_PATH) {
08083 res = cmd;
08084 goto out;
08085 }
08086 } else
08087 cmd = ast_play_and_wait(chan, "vm-nomore");
08088 break;
08089 case '9':
08090 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
08091
08092 cmd = 0;
08093 break;
08094 }
08095 if (useadsi)
08096 adsi_folders(chan, 1, "Save to folder...");
08097 cmd = get_folder2(chan, "vm-savefolder", 1);
08098 box = 0;
08099 if (cmd == '#') {
08100 cmd = 0;
08101 break;
08102 } else if (cmd > 0) {
08103 box = cmd = cmd - '0';
08104 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
08105 if (cmd == ERROR_LOCK_PATH) {
08106 res = cmd;
08107 goto out;
08108 #ifndef IMAP_STORAGE
08109 } else if (!cmd) {
08110 vms.deleted[vms.curmsg] = 1;
08111 #endif
08112 } else {
08113 vms.deleted[vms.curmsg] = 0;
08114 vms.heard[vms.curmsg] = 0;
08115 }
08116 }
08117 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
08118 if (useadsi)
08119 adsi_message(chan, &vms);
08120 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
08121 if (!cmd) {
08122 cmd = ast_play_and_wait(chan, "vm-message");
08123 if (!cmd)
08124 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
08125 if (!cmd)
08126 cmd = ast_play_and_wait(chan, "vm-savedto");
08127 if (!cmd)
08128 cmd = vm_play_folder_name(chan, vms.fn);
08129 } else {
08130 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
08131 }
08132 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
08133 if (vms.curmsg < vms.lastmsg) {
08134 vms.curmsg++;
08135 cmd = play_message(chan, vmu, &vms);
08136 } else {
08137 cmd = ast_play_and_wait(chan, "vm-nomore");
08138 }
08139 }
08140 break;
08141 case '*':
08142 if (!vms.starting) {
08143 cmd = ast_play_and_wait(chan, "vm-onefor");
08144 if (!strncasecmp(chan->language, "he", 2)) {
08145 cmd = ast_play_and_wait(chan, "vm-for");
08146 }
08147 if (!cmd)
08148 cmd = vm_play_folder_name(chan, vms.vmbox);
08149 if (!cmd)
08150 cmd = ast_play_and_wait(chan, "vm-opts");
08151 if (!cmd)
08152 cmd = vm_instructions(chan, &vms, 1);
08153 } else
08154 cmd = 0;
08155 break;
08156 case '0':
08157 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
08158 if (useadsi)
08159 adsi_status(chan, &vms);
08160 break;
08161 default:
08162 cmd = vm_instructions(chan, &vms, 0);
08163 break;
08164 }
08165 }
08166 if ((cmd == 't') || (cmd == '#')) {
08167
08168 res = 0;
08169 } else {
08170
08171 res = -1;
08172 }
08173
08174 out:
08175 if (res > -1) {
08176 ast_stopstream(chan);
08177 adsi_goodbye(chan);
08178 if (valid && res != OPERATOR_EXIT) {
08179 if (silentexit)
08180 res = ast_play_and_wait(chan, "vm-dialout");
08181 else
08182 res = ast_play_and_wait(chan, "vm-goodbye");
08183 }
08184 if ((valid && res > 0) || res == OPERATOR_EXIT) {
08185 res = 0;
08186 }
08187 if (useadsi)
08188 ast_adsi_unload_session(chan);
08189 }
08190 if (vmu)
08191 close_mailbox(&vms, vmu);
08192 if (valid) {
08193 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
08194 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
08195 run_externnotify(vmu->context, vmu->mailbox);
08196 }
08197 #ifdef IMAP_STORAGE
08198
08199 if (option_debug > 2)
08200 ast_log(LOG_DEBUG, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted,expungeonhangup);
08201 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
08202 ast_mutex_lock(&vms.lock);
08203 #ifdef HAVE_IMAP_TK2006
08204 if (LEVELUIDPLUS (vms.mailstream)) {
08205 mail_expunge_full(vms.mailstream,NIL,EX_UID);
08206 } else
08207 #endif
08208 mail_expunge(vms.mailstream);
08209 ast_mutex_unlock(&vms.lock);
08210 }
08211
08212
08213 if (vmu) {
08214 vmstate_delete(&vms);
08215 }
08216 #endif
08217 if (vmu)
08218 free_user(vmu);
08219 if (vms.deleted)
08220 free(vms.deleted);
08221 if (vms.heard)
08222 free(vms.heard);
08223
08224 #ifdef IMAP_STORAGE
08225 pthread_setspecific(ts_vmstate.key, NULL);
08226 #endif
08227 ast_module_user_remove(u);
08228 return res;
08229 }
08230
08231 static int vm_exec(struct ast_channel *chan, void *data)
08232 {
08233 int res = 0;
08234 struct ast_module_user *u;
08235 char *tmp;
08236 struct leave_vm_options leave_options;
08237 struct ast_flags flags = { 0 };
08238 static int deprecate_warning = 0;
08239 char *opts[OPT_ARG_ARRAY_SIZE];
08240 AST_DECLARE_APP_ARGS(args,
08241 AST_APP_ARG(argv0);
08242 AST_APP_ARG(argv1);
08243 );
08244
08245 u = ast_module_user_add(chan);
08246
08247 memset(&leave_options, 0, sizeof(leave_options));
08248
08249 if (chan->_state != AST_STATE_UP)
08250 ast_answer(chan);
08251
08252 if (!ast_strlen_zero(data)) {
08253 tmp = ast_strdupa(data);
08254 AST_STANDARD_APP_ARGS(args, tmp);
08255 if (args.argc == 2) {
08256 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
08257 ast_module_user_remove(u);
08258 return -1;
08259 }
08260 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_PRIORITY_JUMP);
08261 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
08262 int gain;
08263
08264 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
08265 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
08266 ast_module_user_remove(u);
08267 return -1;
08268 } else {
08269 leave_options.record_gain = (signed char) gain;
08270 }
08271 }
08272 } else {
08273
08274 int old = 0;
08275 char *orig_argv0 = args.argv0;
08276 while (*(args.argv0)) {
08277 if (*(args.argv0) == 's') {
08278 old = 1;
08279 ast_set_flag(&leave_options, OPT_SILENT);
08280 } else if (*(args.argv0) == 'b') {
08281 old = 1;
08282 ast_set_flag(&leave_options, OPT_BUSY_GREETING);
08283 } else if (*(args.argv0) == 'u') {
08284 old = 1;
08285 ast_set_flag(&leave_options, OPT_UNAVAIL_GREETING);
08286 } else if (*(args.argv0) == 'j') {
08287 old = 1;
08288 ast_set_flag(&leave_options, OPT_PRIORITY_JUMP);
08289 } else
08290 break;
08291 (args.argv0)++;
08292 }
08293 if (!deprecate_warning && old) {
08294 deprecate_warning = 1;
08295 ast_log(LOG_WARNING, "Prefixing the mailbox with an option is deprecated ('%s').\n", orig_argv0);
08296 ast_log(LOG_WARNING, "Please move all leading options to the second argument.\n");
08297 }
08298 }
08299 } else {
08300 char tmp[256];
08301 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
08302 if (res < 0) {
08303 ast_module_user_remove(u);
08304 return res;
08305 }
08306 if (ast_strlen_zero(tmp)) {
08307 ast_module_user_remove(u);
08308 return 0;
08309 }
08310 args.argv0 = ast_strdupa(tmp);
08311 }
08312
08313 res = leave_voicemail(chan, args.argv0, &leave_options);
08314 if (res == 't') {
08315 ast_play_and_wait(chan, "vm-goodbye");
08316 res = 0;
08317 }
08318
08319 if (res == OPERATOR_EXIT) {
08320 res = 0;
08321 }
08322
08323 if (res == ERROR_LOCK_PATH) {
08324 ast_log(LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
08325
08326 if (ast_test_flag(&leave_options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
08327 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
08328 ast_log(LOG_WARNING, "Extension %s, priority %d doesn't exist.\n", chan->exten, chan->priority + 101);
08329 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
08330 res = 0;
08331 }
08332
08333 ast_module_user_remove(u);
08334
08335 return res;
08336 }
08337
08338 static struct ast_vm_user *find_or_create(char *context, char *mbox)
08339 {
08340 struct ast_vm_user *vmu;
08341 AST_LIST_TRAVERSE(&users, vmu, list) {
08342 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mbox, vmu->mailbox)) {
08343 if (strcasecmp(vmu->context, context)) {
08344 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
08345 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
08346 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
08347 \n\tamend your voicemail.conf file to avoid this situation.\n", mbox);
08348 }
08349 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", mbox);
08350 return NULL;
08351 }
08352 if (!strcasecmp(context, vmu->context) && !strcasecmp(mbox, vmu->mailbox)) {
08353 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", mbox, context);
08354 return NULL;
08355 }
08356 }
08357
08358 if ((vmu = ast_calloc(1, sizeof(*vmu)))) {
08359 ast_copy_string(vmu->context, context, sizeof(vmu->context));
08360 ast_copy_string(vmu->mailbox, mbox, sizeof(vmu->mailbox));
08361 AST_LIST_INSERT_TAIL(&users, vmu, list);
08362 }
08363 return vmu;
08364 }
08365
08366 static int append_mailbox(char *context, char *mbox, char *data)
08367 {
08368
08369 char *tmp;
08370 char *stringp;
08371 char *s;
08372 struct ast_vm_user *vmu;
08373
08374 tmp = ast_strdupa(data);
08375
08376 if ((vmu = find_or_create(context, mbox))) {
08377 populate_defaults(vmu);
08378
08379 stringp = tmp;
08380 if ((s = strsep(&stringp, ",")))
08381 ast_copy_string(vmu->password, s, sizeof(vmu->password));
08382 if (stringp && (s = strsep(&stringp, ",")))
08383 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
08384 if (stringp && (s = strsep(&stringp, ",")))
08385 ast_copy_string(vmu->email, s, sizeof(vmu->email));
08386 if (stringp && (s = strsep(&stringp, ",")))
08387 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
08388 if (stringp && (s = strsep(&stringp, ",")))
08389 apply_options(vmu, s);
08390 }
08391 return 0;
08392 }
08393
08394 static int vm_box_exists(struct ast_channel *chan, void *data)
08395 {
08396 struct ast_module_user *u;
08397 struct ast_vm_user svm;
08398 char *context, *box;
08399 int priority_jump = 0;
08400 AST_DECLARE_APP_ARGS(args,
08401 AST_APP_ARG(mbox);
08402 AST_APP_ARG(options);
08403 );
08404
08405 if (ast_strlen_zero(data)) {
08406 ast_log(LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
08407 return -1;
08408 }
08409
08410 u = ast_module_user_add(chan);
08411
08412 box = ast_strdupa(data);
08413
08414 AST_STANDARD_APP_ARGS(args, box);
08415
08416 if (args.options) {
08417 if (strchr(args.options, 'j'))
08418 priority_jump = 1;
08419 }
08420
08421 if ((context = strchr(args.mbox, '@'))) {
08422 *context = '\0';
08423 context++;
08424 }
08425
08426 if (find_user(&svm, context, args.mbox)) {
08427 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
08428 if (priority_jump || ast_opt_priority_jumping)
08429 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
08430 ast_log(LOG_WARNING, "VM box %s@%s exists, but extension %s, priority %d doesn't exist\n", box, context, chan->exten, chan->priority + 101);
08431 } else
08432 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
08433 ast_module_user_remove(u);
08434 return 0;
08435 }
08436
08437 static int vmauthenticate(struct ast_channel *chan, void *data)
08438 {
08439 struct ast_module_user *u;
08440 char *s = data, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION] = "";
08441 struct ast_vm_user vmus;
08442 char *options = NULL;
08443 int silent = 0, skipuser = 0;
08444 int res = -1;
08445
08446 u = ast_module_user_add(chan);
08447
08448 if (s) {
08449 s = ast_strdupa(s);
08450 user = strsep(&s, "|");
08451 options = strsep(&s, "|");
08452 if (user) {
08453 s = user;
08454 user = strsep(&s, "@");
08455 context = strsep(&s, "");
08456 if (!ast_strlen_zero(user))
08457 skipuser++;
08458 ast_copy_string(mailbox, user, sizeof(mailbox));
08459 }
08460 }
08461
08462 if (options) {
08463 silent = (strchr(options, 's')) != NULL;
08464 }
08465
08466 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
08467 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
08468 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
08469 ast_play_and_wait(chan, "auth-thankyou");
08470 res = 0;
08471 }
08472
08473 ast_module_user_remove(u);
08474 return res;
08475 }
08476
08477 static char voicemail_show_users_help[] =
08478 "Usage: voicemail show users [for <context>]\n"
08479 " Lists all mailboxes currently set up\n";
08480
08481 static char voicemail_show_zones_help[] =
08482 "Usage: voicemail show zones\n"
08483 " Lists zone message formats\n";
08484
08485 static int handle_voicemail_show_users(int fd, int argc, char *argv[])
08486 {
08487 struct ast_vm_user *vmu;
08488 char *output_format = "%-10s %-5s %-25s %-10s %6s\n";
08489
08490 if ((argc < 3) || (argc > 5) || (argc == 4)) return RESULT_SHOWUSAGE;
08491 else if ((argc == 5) && strcmp(argv[3],"for")) return RESULT_SHOWUSAGE;
08492
08493 AST_LIST_LOCK(&users);
08494 if (!AST_LIST_EMPTY(&users)) {
08495 if (argc == 3)
08496 ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
08497 else {
08498 int count = 0;
08499 AST_LIST_TRAVERSE(&users, vmu, list) {
08500 if (!strcmp(argv[4],vmu->context))
08501 count++;
08502 }
08503 if (count) {
08504 ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
08505 } else {
08506 ast_cli(fd, "No such voicemail context \"%s\"\n", argv[4]);
08507 AST_LIST_UNLOCK(&users);
08508 return RESULT_FAILURE;
08509 }
08510 }
08511 AST_LIST_TRAVERSE(&users, vmu, list) {
08512 int newmsgs = 0, oldmsgs = 0;
08513 char count[12], tmp[256] = "";
08514
08515 if ((argc == 3) || ((argc == 5) && !strcmp(argv[4],vmu->context))) {
08516 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
08517 inboxcount(tmp, &newmsgs, &oldmsgs);
08518 snprintf(count,sizeof(count),"%d",newmsgs);
08519 ast_cli(fd, output_format, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
08520 }
08521 }
08522 } else {
08523 ast_cli(fd, "There are no voicemail users currently defined\n");
08524 AST_LIST_UNLOCK(&users);
08525 return RESULT_FAILURE;
08526 }
08527 AST_LIST_UNLOCK(&users);
08528 return RESULT_SUCCESS;
08529 }
08530
08531 static int handle_voicemail_show_zones(int fd, int argc, char *argv[])
08532 {
08533 struct vm_zone *zone;
08534 char *output_format = "%-15s %-20s %-45s\n";
08535 int res = RESULT_SUCCESS;
08536
08537 if (argc != 3)
08538 return RESULT_SHOWUSAGE;
08539
08540 AST_LIST_LOCK(&zones);
08541 if (!AST_LIST_EMPTY(&zones)) {
08542 ast_cli(fd, output_format, "Zone", "Timezone", "Message Format");
08543 AST_LIST_TRAVERSE(&zones, zone, list) {
08544 ast_cli(fd, output_format, zone->name, zone->timezone, zone->msg_format);
08545 }
08546 } else {
08547 ast_cli(fd, "There are no voicemail zones currently defined\n");
08548 res = RESULT_FAILURE;
08549 }
08550 AST_LIST_UNLOCK(&zones);
08551
08552 return res;
08553 }
08554
08555 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
08556 {
08557 int which = 0;
08558 int wordlen;
08559 struct ast_vm_user *vmu;
08560 const char *context = "";
08561
08562
08563 if (pos > 4)
08564 return NULL;
08565 if (pos == 3)
08566 return (state == 0) ? ast_strdup("for") : NULL;
08567 wordlen = strlen(word);
08568 AST_LIST_TRAVERSE(&users, vmu, list) {
08569 if (!strncasecmp(word, vmu->context, wordlen)) {
08570 if (context && strcmp(context, vmu->context) && ++which > state)
08571 return ast_strdup(vmu->context);
08572
08573 context = vmu->context;
08574 }
08575 }
08576 return NULL;
08577 }
08578
08579 static struct ast_cli_entry cli_show_voicemail_users_deprecated = {
08580 { "show", "voicemail", "users", NULL },
08581 handle_voicemail_show_users, NULL,
08582 NULL, complete_voicemail_show_users };
08583
08584 static struct ast_cli_entry cli_show_voicemail_zones_deprecated = {
08585 { "show", "voicemail", "zones", NULL },
08586 handle_voicemail_show_zones, NULL,
08587 NULL, NULL };
08588
08589 static struct ast_cli_entry cli_voicemail[] = {
08590 { { "voicemail", "show", "users", NULL },
08591 handle_voicemail_show_users, "List defined voicemail boxes",
08592 voicemail_show_users_help, complete_voicemail_show_users, &cli_show_voicemail_users_deprecated },
08593
08594 { { "voicemail", "show", "zones", NULL },
08595 handle_voicemail_show_zones, "List zone message formats",
08596 voicemail_show_zones_help, NULL, &cli_show_voicemail_zones_deprecated },
08597 };
08598
08599 static void free_vm_users(void)
08600 {
08601 struct ast_vm_user *cur;
08602 struct vm_zone *zcur;
08603
08604 AST_LIST_LOCK(&users);
08605 while ((cur = AST_LIST_REMOVE_HEAD(&users, list))) {
08606 ast_set_flag(cur, VM_ALLOCED);
08607 free_user(cur);
08608 }
08609 AST_LIST_UNLOCK(&users);
08610
08611 AST_LIST_LOCK(&zones);
08612 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list))) {
08613 free_zone(zcur);
08614 }
08615 AST_LIST_UNLOCK(&zones);
08616 }
08617
08618 static int load_config(void)
08619 {
08620 struct ast_vm_user *cur;
08621 struct ast_config *cfg, *ucfg;
08622 char *cat;
08623 struct ast_variable *var;
08624 const char *notifystr = NULL;
08625 const char *smdistr = NULL;
08626 const char *astattach;
08627 const char *astsearch;
08628 const char *astsaycid;
08629 const char *send_voicemail;
08630 #ifdef IMAP_STORAGE
08631 const char *imap_server;
08632 const char *imap_port;
08633 const char *imap_flags;
08634 const char *imap_folder;
08635 const char *auth_user;
08636 const char *auth_password;
08637 const char *expunge_on_hangup;
08638 const char *imap_timeout;
08639 #endif
08640 const char *astcallop;
08641 const char *astreview;
08642 const char *asttempgreetwarn;
08643 const char *astskipcmd;
08644 const char *asthearenv;
08645 const char *astsaydurationinfo;
08646 const char *astsaydurationminfo;
08647 const char *silencestr;
08648 const char *maxmsgstr;
08649 const char *astdirfwd;
08650 const char *thresholdstr;
08651 const char *fmt;
08652 const char *astemail;
08653 const char *ucontext;
08654 const char *astmailcmd = SENDMAIL;
08655 const char *astpreprocesscmd;
08656 const char *astpreprocessfmt;
08657 const char *astforcename;
08658 const char *astforcegreet;
08659 const char *s;
08660 char *q,*stringp, *tmp;
08661 const char *dialoutcxt = NULL;
08662 const char *callbackcxt = NULL;
08663 const char *exitcxt = NULL;
08664 const char *extpc;
08665 const char *emaildateformatstr;
08666 const char *volgainstr;
08667 int x;
08668 int tmpadsi[4];
08669
08670 cfg = ast_config_load(VOICEMAIL_CONFIG);
08671
08672 free_vm_users();
08673
08674 AST_LIST_LOCK(&users);
08675
08676 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
08677
08678 if (cfg) {
08679
08680
08681 if (!(ucontext = ast_variable_retrieve(cfg, "general", "userscontext")))
08682 ucontext = "default";
08683 ast_copy_string(userscontext, ucontext, sizeof(userscontext));
08684
08685 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
08686 astattach = "yes";
08687 ast_set2_flag((&globalflags), ast_true(astattach), VM_ATTACH);
08688
08689 if (!(astsearch = ast_variable_retrieve(cfg, "general", "searchcontexts")))
08690 astsearch = "no";
08691 ast_set2_flag((&globalflags), ast_true(astsearch), VM_SEARCH);
08692
08693 volgain = 0.0;
08694 if ((volgainstr = ast_variable_retrieve(cfg, "general", "volgain")))
08695 sscanf(volgainstr, "%30lf", &volgain);
08696
08697 #ifdef ODBC_STORAGE
08698 strcpy(odbc_database, "asterisk");
08699 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
08700 ast_copy_string(odbc_database, thresholdstr, sizeof(odbc_database));
08701 }
08702 strcpy(odbc_table, "voicemessages");
08703 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbctable"))) {
08704 ast_copy_string(odbc_table, thresholdstr, sizeof(odbc_table));
08705 }
08706 #endif
08707
08708 strcpy(mailcmd, SENDMAIL);
08709 if ((astmailcmd = ast_variable_retrieve(cfg, "general", "mailcmd")))
08710 ast_copy_string(mailcmd, astmailcmd, sizeof(mailcmd));
08711
08712
08713 if ((astpreprocesscmd = ast_variable_retrieve(cfg, "general", "preprocesscmd"))) {
08714 ast_copy_string(preprocesscmd, astpreprocesscmd, sizeof(preprocesscmd));
08715 if ((astpreprocessfmt = ast_variable_retrieve(cfg, "general", "preprocessfmt")))
08716 ast_copy_string(preprocessfmt, astpreprocessfmt, sizeof(preprocessfmt));
08717 else
08718 ast_log(LOG_WARNING, "Empty 'preprocessfmt'. Using default format value\n");
08719 }
08720
08721 maxsilence = 0;
08722 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
08723 maxsilence = atoi(silencestr);
08724 if (maxsilence > 0)
08725 maxsilence *= 1000;
08726 }
08727
08728 if (!(maxmsgstr = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
08729 maxmsg = MAXMSG;
08730 } else {
08731 maxmsg = atoi(maxmsgstr);
08732 if (maxmsg <= 0) {
08733 ast_log(LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", maxmsgstr, MAXMSG);
08734 maxmsg = MAXMSG;
08735 } else if (maxmsg > MAXMSGLIMIT) {
08736 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, maxmsgstr);
08737 maxmsg = MAXMSGLIMIT;
08738 }
08739 }
08740
08741
08742 if ((emaildateformatstr = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
08743 ast_copy_string(emaildateformat, emaildateformatstr, sizeof(emaildateformat));
08744 }
08745
08746
08747 if ((extpc = ast_variable_retrieve(cfg, "general", "externpass"))) {
08748 ast_copy_string(ext_pass_cmd,extpc,sizeof(ext_pass_cmd));
08749 }
08750 #ifdef IMAP_STORAGE
08751
08752 if ((imap_server = ast_variable_retrieve(cfg, "general", "imapserver"))) {
08753 ast_copy_string(imapserver, imap_server, sizeof(imapserver));
08754 } else {
08755 ast_copy_string(imapserver,"localhost", sizeof(imapserver));
08756 }
08757
08758 if ((imap_port = ast_variable_retrieve(cfg, "general", "imapport"))) {
08759 ast_copy_string(imapport, imap_port, sizeof(imapport));
08760 } else {
08761 ast_copy_string(imapport,"143", sizeof(imapport));
08762 }
08763
08764 if ((imap_flags = ast_variable_retrieve(cfg, "general", "imapflags"))) {
08765 ast_copy_string(imapflags, imap_flags, sizeof(imapflags));
08766 }
08767
08768 if ((auth_user = ast_variable_retrieve(cfg, "general", "authuser"))) {
08769 ast_copy_string(authuser, auth_user, sizeof(authuser));
08770 }
08771
08772 if ((auth_password = ast_variable_retrieve(cfg, "general", "authpassword"))) {
08773 ast_copy_string(authpassword, auth_password, sizeof(authpassword));
08774 }
08775
08776 if ((expunge_on_hangup = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
08777 if (ast_false(expunge_on_hangup))
08778 expungeonhangup = 0;
08779 else
08780 expungeonhangup = 1;
08781 } else {
08782 expungeonhangup = 1;
08783 }
08784
08785 if ((imap_folder = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
08786 ast_copy_string(imapfolder, imap_folder, sizeof(imapfolder));
08787 } else {
08788 ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
08789 }
08790
08791
08792
08793
08794
08795
08796 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
08797 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(imap_timeout)));
08798 } else {
08799 mail_parameters(NIL, SET_READTIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08800 }
08801
08802 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
08803 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(imap_timeout)));
08804 } else {
08805 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08806 }
08807
08808 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
08809 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(imap_timeout)));
08810 } else {
08811 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08812 }
08813
08814 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
08815 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(imap_timeout)));
08816 } else {
08817 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08818 }
08819
08820
08821 imapversion++;
08822 #endif
08823
08824
08825 if ((notifystr = ast_variable_retrieve(cfg, "general", "externnotify"))) {
08826 ast_copy_string(externnotify, notifystr, sizeof(externnotify));
08827 if (option_debug > 2)
08828 ast_log(LOG_DEBUG, "found externnotify: %s\n", externnotify);
08829 if (!strcasecmp(externnotify, "smdi")) {
08830 if (option_debug)
08831 ast_log(LOG_DEBUG, "Using SMDI for external voicemail notification\n");
08832 if ((smdistr = ast_variable_retrieve(cfg, "general", "smdiport"))) {
08833 smdi_iface = ast_smdi_interface_find(smdistr);
08834 } else {
08835 if (option_debug)
08836 ast_log(LOG_DEBUG, "No SMDI interface set, trying default (/dev/ttyS0)\n");
08837 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
08838 }
08839
08840 if (!smdi_iface) {
08841 ast_log(LOG_ERROR, "No valid SMDI interface specfied, disabling external voicemail notification\n");
08842 externnotify[0] = '\0';
08843 }
08844 }
08845 } else {
08846 externnotify[0] = '\0';
08847 }
08848
08849
08850 silencethreshold = 256;
08851 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
08852 silencethreshold = atoi(thresholdstr);
08853
08854 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
08855 astemail = ASTERISK_USERNAME;
08856 ast_copy_string(serveremail, astemail, sizeof(serveremail));
08857
08858 vmmaxmessage = 0;
08859 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
08860 if (sscanf(s, "%30d", &x) == 1) {
08861 vmmaxmessage = x;
08862 } else {
08863 ast_log(LOG_WARNING, "Invalid max message time length\n");
08864 }
08865 }
08866
08867 vmminmessage = 0;
08868 if ((s = ast_variable_retrieve(cfg, "general", "minmessage"))) {
08869 if (sscanf(s, "%30d", &x) == 1) {
08870 vmminmessage = x;
08871 if (maxsilence / 1000 >= vmminmessage)
08872 ast_log(LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
08873 } else {
08874 ast_log(LOG_WARNING, "Invalid min message time length\n");
08875 }
08876 }
08877 fmt = ast_variable_retrieve(cfg, "general", "format");
08878 if (!fmt) {
08879 fmt = "wav";
08880 } else {
08881 tmp = ast_strdupa(fmt);
08882 fmt = ast_format_str_reduce(tmp);
08883 if (!fmt) {
08884 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
08885 fmt = "wav";
08886 }
08887 }
08888
08889 ast_copy_string(vmfmts, fmt, sizeof(vmfmts));
08890
08891 skipms = 3000;
08892 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
08893 if (sscanf(s, "%30d", &x) == 1) {
08894 maxgreet = x;
08895 } else {
08896 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
08897 }
08898 }
08899
08900 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
08901 if (sscanf(s, "%30d", &x) == 1) {
08902 skipms = x;
08903 } else {
08904 ast_log(LOG_WARNING, "Invalid skipms value\n");
08905 }
08906 }
08907
08908 maxlogins = 3;
08909 if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
08910 if (sscanf(s, "%30d", &x) == 1) {
08911 maxlogins = x;
08912 } else {
08913 ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
08914 }
08915 }
08916
08917
08918 if (!(astforcename = ast_variable_retrieve(cfg, "general", "forcename")))
08919 astforcename = "no";
08920 ast_set2_flag((&globalflags), ast_true(astforcename), VM_FORCENAME);
08921
08922
08923 if (!(astforcegreet = ast_variable_retrieve(cfg, "general", "forcegreetings")))
08924 astforcegreet = "no";
08925 ast_set2_flag((&globalflags), ast_true(astforcegreet), VM_FORCEGREET);
08926
08927 if ((s = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))){
08928 if (option_debug > 2)
08929 ast_log(LOG_DEBUG,"VM_CID Internal context string: %s\n",s);
08930 stringp = ast_strdupa(s);
08931 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
08932 if (!ast_strlen_zero(stringp)) {
08933 q = strsep(&stringp,",");
08934 while ((*q == ' ')||(*q == '\t'))
08935 q++;
08936 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
08937 if (option_debug > 2)
08938 ast_log(LOG_DEBUG,"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
08939 } else {
08940 cidinternalcontexts[x][0] = '\0';
08941 }
08942 }
08943 }
08944 if (!(astreview = ast_variable_retrieve(cfg, "general", "review"))){
08945 if (option_debug)
08946 ast_log(LOG_DEBUG,"VM Review Option disabled globally\n");
08947 astreview = "no";
08948 }
08949 ast_set2_flag((&globalflags), ast_true(astreview), VM_REVIEW);
08950
08951
08952 if (!(asttempgreetwarn = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
08953 if (option_debug)
08954 ast_log(LOG_DEBUG, "VM Temperary Greeting Reminder Option disabled globally\n");
08955 asttempgreetwarn = "no";
08956 } else {
08957 if (option_debug)
08958 ast_log(LOG_DEBUG, "VM Temperary Greeting Reminder Option enabled globally\n");
08959 }
08960 ast_set2_flag((&globalflags), ast_true(asttempgreetwarn), VM_TEMPGREETWARN);
08961
08962 if (!(astcallop = ast_variable_retrieve(cfg, "general", "operator"))){
08963 if (option_debug)
08964 ast_log(LOG_DEBUG,"VM Operator break disabled globally\n");
08965 astcallop = "no";
08966 }
08967 ast_set2_flag((&globalflags), ast_true(astcallop), VM_OPERATOR);
08968
08969 if (!(astsaycid = ast_variable_retrieve(cfg, "general", "saycid"))) {
08970 if (option_debug)
08971 ast_log(LOG_DEBUG,"VM CID Info before msg disabled globally\n");
08972 astsaycid = "no";
08973 }
08974 ast_set2_flag((&globalflags), ast_true(astsaycid), VM_SAYCID);
08975
08976 if (!(send_voicemail = ast_variable_retrieve(cfg,"general", "sendvoicemail"))){
08977 if (option_debug)
08978 ast_log(LOG_DEBUG,"Send Voicemail msg disabled globally\n");
08979 send_voicemail = "no";
08980 }
08981 ast_set2_flag((&globalflags), ast_true(send_voicemail), VM_SVMAIL);
08982
08983 if (!(asthearenv = ast_variable_retrieve(cfg, "general", "envelope"))) {
08984 if (option_debug)
08985 ast_log(LOG_DEBUG,"ENVELOPE before msg enabled globally\n");
08986 asthearenv = "yes";
08987 }
08988 ast_set2_flag((&globalflags), ast_true(asthearenv), VM_ENVELOPE);
08989
08990 if (!(astsaydurationinfo = ast_variable_retrieve(cfg, "general", "sayduration"))) {
08991 if (option_debug)
08992 ast_log(LOG_DEBUG,"Duration info before msg enabled globally\n");
08993 astsaydurationinfo = "yes";
08994 }
08995 ast_set2_flag((&globalflags), ast_true(astsaydurationinfo), VM_SAYDURATION);
08996
08997 saydurationminfo = 2;
08998 if ((astsaydurationminfo = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
08999 if (sscanf(astsaydurationminfo, "%30d", &x) == 1) {
09000 saydurationminfo = x;
09001 } else {
09002 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
09003 }
09004 }
09005
09006 if (!(astskipcmd = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
09007 if (option_debug)
09008 ast_log(LOG_DEBUG,"We are not going to skip to the next msg after save/delete\n");
09009 astskipcmd = "no";
09010 }
09011 ast_set2_flag((&globalflags), ast_true(astskipcmd), VM_SKIPAFTERCMD);
09012
09013 if ((dialoutcxt = ast_variable_retrieve(cfg, "general", "dialout"))) {
09014 ast_copy_string(dialcontext, dialoutcxt, sizeof(dialcontext));
09015 if (option_debug)
09016 ast_log(LOG_DEBUG, "found dialout context: %s\n", dialcontext);
09017 } else {
09018 dialcontext[0] = '\0';
09019 }
09020
09021 if ((callbackcxt = ast_variable_retrieve(cfg, "general", "callback"))) {
09022 ast_copy_string(callcontext, callbackcxt, sizeof(callcontext));
09023 if (option_debug)
09024 ast_log(LOG_DEBUG, "found callback context: %s\n", callcontext);
09025 } else {
09026 callcontext[0] = '\0';
09027 }
09028
09029 if ((exitcxt = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
09030 ast_copy_string(exitcontext, exitcxt, sizeof(exitcontext));
09031 if (option_debug)
09032 ast_log(LOG_DEBUG, "found operator context: %s\n", exitcontext);
09033 } else {
09034 exitcontext[0] = '\0';
09035 }
09036
09037 if (!(astdirfwd = ast_variable_retrieve(cfg, "general", "usedirectory")))
09038 astdirfwd = "no";
09039 ast_set2_flag((&globalflags), ast_true(astdirfwd), VM_DIRECFORWARD);
09040 if ((ucfg = ast_config_load("users.conf"))) {
09041 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
09042 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
09043 continue;
09044 if ((cur = find_or_create(userscontext, cat))) {
09045 populate_defaults(cur);
09046 apply_options_full(cur, ast_variable_browse(ucfg, cat));
09047 ast_copy_string(cur->context, userscontext, sizeof(cur->context));
09048 }
09049 }
09050 ast_config_destroy(ucfg);
09051 }
09052 cat = ast_category_browse(cfg, NULL);
09053 while (cat) {
09054 if (strcasecmp(cat, "general")) {
09055 var = ast_variable_browse(cfg, cat);
09056 if (strcasecmp(cat, "zonemessages")) {
09057
09058 while (var) {
09059 append_mailbox(cat, var->name, var->value);
09060 var = var->next;
09061 }
09062 } else {
09063
09064 while (var) {
09065 struct vm_zone *z;
09066 if ((z = ast_malloc(sizeof(*z)))) {
09067 char *msg_format, *timezone;
09068 msg_format = ast_strdupa(var->value);
09069 timezone = strsep(&msg_format, "|");
09070 if (msg_format) {
09071 ast_copy_string(z->name, var->name, sizeof(z->name));
09072 ast_copy_string(z->timezone, timezone, sizeof(z->timezone));
09073 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
09074 AST_LIST_LOCK(&zones);
09075 AST_LIST_INSERT_HEAD(&zones, z, list);
09076 AST_LIST_UNLOCK(&zones);
09077 } else {
09078 ast_log(LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
09079 free(z);
09080 }
09081 } else {
09082 free(z);
09083 AST_LIST_UNLOCK(&users);
09084 ast_config_destroy(cfg);
09085 return -1;
09086 }
09087 var = var->next;
09088 }
09089 }
09090 }
09091 cat = ast_category_browse(cfg, cat);
09092 }
09093 memset(fromstring,0,sizeof(fromstring));
09094 memset(pagerfromstring,0,sizeof(pagerfromstring));
09095 memset(emailtitle,0,sizeof(emailtitle));
09096 strcpy(charset, "ISO-8859-1");
09097 if (emailbody) {
09098 free(emailbody);
09099 emailbody = NULL;
09100 }
09101 if (emailsubject) {
09102 free(emailsubject);
09103 emailsubject = NULL;
09104 }
09105 if (pagerbody) {
09106 free(pagerbody);
09107 pagerbody = NULL;
09108 }
09109 if (pagersubject) {
09110 free(pagersubject);
09111 pagersubject = NULL;
09112 }
09113 if ((s = ast_variable_retrieve(cfg, "general", "pbxskip")))
09114 ast_set2_flag((&globalflags), ast_true(s), VM_PBXSKIP);
09115 if ((s = ast_variable_retrieve(cfg, "general", "fromstring")))
09116 ast_copy_string(fromstring,s,sizeof(fromstring));
09117 if ((s = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
09118 ast_copy_string(pagerfromstring,s,sizeof(pagerfromstring));
09119 if ((s = ast_variable_retrieve(cfg, "general", "charset")))
09120 ast_copy_string(charset,s,sizeof(charset));
09121 if ((s = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
09122 sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
09123 for (x = 0; x < 4; x++) {
09124 memcpy(&adsifdn[x], &tmpadsi[x], 1);
09125 }
09126 }
09127 if ((s = ast_variable_retrieve(cfg, "general", "adsisec"))) {
09128 sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
09129 for (x = 0; x < 4; x++) {
09130 memcpy(&adsisec[x], &tmpadsi[x], 1);
09131 }
09132 }
09133 if ((s = ast_variable_retrieve(cfg, "general", "adsiver")))
09134 if (atoi(s)) {
09135 adsiver = atoi(s);
09136 }
09137 if ((s = ast_variable_retrieve(cfg, "general", "emailtitle"))) {
09138 ast_log(LOG_NOTICE, "Keyword 'emailtitle' is DEPRECATED, please use 'emailsubject' instead.\n");
09139 ast_copy_string(emailtitle,s,sizeof(emailtitle));
09140 }
09141 if ((s = ast_variable_retrieve(cfg, "general", "emailsubject")))
09142 emailsubject = ast_strdup(s);
09143 if ((s = ast_variable_retrieve(cfg, "general", "emailbody"))) {
09144 char *tmpread, *tmpwrite;
09145 emailbody = ast_strdup(s);
09146
09147
09148 tmpread = tmpwrite = emailbody;
09149 while ((tmpwrite = strchr(tmpread,'\\'))) {
09150 switch (tmpwrite[1]) {
09151 case 'r':
09152 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09153 *tmpwrite = '\r';
09154 break;
09155 case 'n':
09156 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09157 *tmpwrite = '\n';
09158 break;
09159 case 't':
09160 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09161 *tmpwrite = '\t';
09162 break;
09163 default:
09164 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
09165 }
09166 tmpread = tmpwrite + 1;
09167 }
09168 }
09169 if ((s = ast_variable_retrieve(cfg, "general", "tz"))) {
09170 ast_copy_string(zonetag, s, sizeof(zonetag));
09171 }
09172 if ((s = ast_variable_retrieve(cfg, "general", "pagersubject")))
09173 pagersubject = ast_strdup(s);
09174 if ((s = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
09175 char *tmpread, *tmpwrite;
09176 pagerbody = ast_strdup(s);
09177
09178
09179 tmpread = tmpwrite = pagerbody;
09180 while ((tmpwrite = strchr(tmpread, '\\'))) {
09181 switch (tmpwrite[1]) {
09182 case 'r':
09183 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09184 *tmpwrite = '\r';
09185 break;
09186 case 'n':
09187 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09188 *tmpwrite = '\n';
09189 break;
09190 case 't':
09191 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09192 *tmpwrite = '\t';
09193 break;
09194 default:
09195 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
09196 }
09197 tmpread = tmpwrite + 1;
09198 }
09199 }
09200 AST_LIST_UNLOCK(&users);
09201 ast_config_destroy(cfg);
09202 return 0;
09203 } else {
09204 AST_LIST_UNLOCK(&users);
09205 ast_log(LOG_WARNING, "Failed to load configuration file.\n");
09206 return 0;
09207 }
09208 }
09209
09210 static int reload(void)
09211 {
09212 return(load_config());
09213 }
09214
09215 static int unload_module(void)
09216 {
09217 int res;
09218
09219 res = ast_unregister_application(app);
09220 res |= ast_unregister_application(app2);
09221 res |= ast_unregister_application(app3);
09222 res |= ast_unregister_application(app4);
09223 ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
09224 ast_uninstall_vm_functions();
09225 ao2_ref(inprocess_container, -1);
09226
09227 ast_module_user_hangup_all();
09228
09229 return res;
09230 }
09231
09232 static int load_module(void)
09233 {
09234 int res;
09235 char *adsi_loaded = ast_module_helper("", "res_adsi", 0, 0, 0, 0);
09236 char *smdi_loaded = ast_module_helper("", "res_smdi", 0, 0, 0, 0);
09237 free(adsi_loaded);
09238 free(smdi_loaded);
09239
09240 if (!adsi_loaded) {
09241 ast_log(LOG_ERROR, "app_voicemail.so depends upon res_adsi.so\n");
09242 return AST_MODULE_LOAD_DECLINE;
09243 }
09244
09245 if (!smdi_loaded) {
09246 ast_log(LOG_ERROR, "app_voicemail.so depends upon res_smdi.so\n");
09247 return AST_MODULE_LOAD_DECLINE;
09248 }
09249
09250 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
09251 return AST_MODULE_LOAD_DECLINE;
09252 }
09253
09254 my_umask = umask(0);
09255 umask(my_umask);
09256 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
09257 res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
09258 res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
09259 res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate);
09260 if (res)
09261 return(res);
09262
09263 if ((res=load_config())) {
09264 return(res);
09265 }
09266
09267 ast_cli_register_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
09268
09269
09270 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
09271
09272 ast_install_vm_functions(has_voicemail, inboxcount, messagecount);
09273
09274 return res;
09275 }
09276
09277 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
09278 {
09279 int cmd = 0;
09280 char destination[80] = "";
09281 int retries = 0;
09282
09283 if (!num) {
09284 if (option_verbose > 2)
09285 ast_verbose( VERBOSE_PREFIX_3 "Destination number will be entered manually\n");
09286 while (retries < 3 && cmd != 't') {
09287 destination[1] = '\0';
09288 destination[0] = cmd = ast_play_and_wait(chan,"vm-enter-num-to-call");
09289 if (!cmd)
09290 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
09291 if (!cmd)
09292 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
09293 if (!cmd) {
09294 cmd = ast_waitfordigit(chan, 6000);
09295 if (cmd)
09296 destination[0] = cmd;
09297 }
09298 if (!cmd) {
09299 retries++;
09300 } else {
09301
09302 if (cmd < 0)
09303 return 0;
09304 if (cmd == '*') {
09305 if (option_verbose > 2)
09306 ast_verbose( VERBOSE_PREFIX_3 "User hit '*' to cancel outgoing call\n");
09307 return 0;
09308 }
09309 if ((cmd = ast_readstring(chan,destination + strlen(destination),sizeof(destination)-1,6000,10000,"#")) < 0)
09310 retries++;
09311 else
09312 cmd = 't';
09313 }
09314 }
09315 if (retries >= 3) {
09316 return 0;
09317 }
09318
09319 } else {
09320 if (option_verbose > 2)
09321 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
09322 ast_copy_string(destination, num, sizeof(destination));
09323 }
09324
09325 if (!ast_strlen_zero(destination)) {
09326 if (destination[strlen(destination) -1 ] == '*')
09327 return 0;
09328 if (option_verbose > 2)
09329 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
09330 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
09331 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
09332 chan->priority = 0;
09333 return 9;
09334 }
09335 return 0;
09336 }
09337
09338 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain)
09339 {
09340 int res = 0;
09341 char filename[PATH_MAX];
09342 struct ast_config *msg_cfg = NULL;
09343 const char *origtime, *context;
09344 char *cid, *name, *num;
09345 int retries = 0;
09346
09347 vms->starting = 0;
09348 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
09349
09350
09351 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
09352 snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
09353 RETRIEVE(vms->curdir, vms->curmsg, vmu);
09354 msg_cfg = ast_config_load(filename);
09355 DISPOSE(vms->curdir, vms->curmsg);
09356 if (!msg_cfg) {
09357 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
09358 return 0;
09359 }
09360
09361 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
09362 ast_config_destroy(msg_cfg);
09363 return 0;
09364 }
09365
09366 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
09367
09368 context = ast_variable_retrieve(msg_cfg, "message", "context");
09369 if (!strncasecmp("macro",context,5))
09370 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
09371 switch (option) {
09372 case 3:
09373 if (!res)
09374 res = play_message_datetime(chan, vmu, origtime, filename);
09375 if (!res)
09376 res = play_message_callerid(chan, vms, cid, context, 0);
09377
09378 res = 't';
09379 break;
09380
09381 case 2:
09382
09383 if (ast_strlen_zero(cid))
09384 break;
09385
09386 ast_callerid_parse(cid, &name, &num);
09387 while ((res > -1) && (res != 't')) {
09388 switch (res) {
09389 case '1':
09390 if (num) {
09391
09392 res = dialout(chan, vmu, num, vmu->callback);
09393 if (res) {
09394 ast_config_destroy(msg_cfg);
09395 return 9;
09396 }
09397 } else {
09398 res = '2';
09399 }
09400 break;
09401
09402 case '2':
09403
09404 if (!ast_strlen_zero(vmu->dialout)) {
09405 res = dialout(chan, vmu, NULL, vmu->dialout);
09406 if (res) {
09407 ast_config_destroy(msg_cfg);
09408 return 9;
09409 }
09410 } else {
09411 if (option_verbose > 2)
09412 ast_verbose( VERBOSE_PREFIX_3 "Caller can not specify callback number - no dialout context available\n");
09413 res = ast_play_and_wait(chan, "vm-sorry");
09414 }
09415 ast_config_destroy(msg_cfg);
09416 return res;
09417 case '*':
09418 res = 't';
09419 break;
09420 case '3':
09421 case '4':
09422 case '5':
09423 case '6':
09424 case '7':
09425 case '8':
09426 case '9':
09427 case '0':
09428
09429 res = ast_play_and_wait(chan, "vm-sorry");
09430 retries++;
09431 break;
09432 default:
09433 if (num) {
09434 if (option_verbose > 2)
09435 ast_verbose( VERBOSE_PREFIX_3 "Confirm CID number '%s' is number to use for callback\n", num);
09436 res = ast_play_and_wait(chan, "vm-num-i-have");
09437 if (!res)
09438 res = play_message_callerid(chan, vms, num, vmu->context, 1);
09439 if (!res)
09440 res = ast_play_and_wait(chan, "vm-tocallnum");
09441
09442 if (!ast_strlen_zero(vmu->dialout)) {
09443 if (!res)
09444 res = ast_play_and_wait(chan, "vm-calldiffnum");
09445 }
09446 } else {
09447 res = ast_play_and_wait(chan, "vm-nonumber");
09448 if (!ast_strlen_zero(vmu->dialout)) {
09449 if (!res)
09450 res = ast_play_and_wait(chan, "vm-toenternumber");
09451 }
09452 }
09453 if (!res)
09454 res = ast_play_and_wait(chan, "vm-star-cancel");
09455 if (!res)
09456 res = ast_waitfordigit(chan, 6000);
09457 if (!res) {
09458 retries++;
09459 if (retries > 3)
09460 res = 't';
09461 }
09462 break;
09463
09464 }
09465 if (res == 't')
09466 res = 0;
09467 else if (res == '*')
09468 res = -1;
09469 }
09470 break;
09471
09472 case 1:
09473
09474 if (ast_strlen_zero(cid))
09475 break;
09476
09477 ast_callerid_parse(cid, &name, &num);
09478 if (!num) {
09479 if (option_verbose > 2)
09480 ast_verbose(VERBOSE_PREFIX_3 "No CID number available, no reply sent\n");
09481 if (!res)
09482 res = ast_play_and_wait(chan, "vm-nonumber");
09483 ast_config_destroy(msg_cfg);
09484 return res;
09485 } else {
09486 struct ast_vm_user vmu2;
09487 if (find_user(&vmu2, vmu->context, num)) {
09488 struct leave_vm_options leave_options;
09489 char mailbox[AST_MAX_EXTENSION * 2 + 2];
09490 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
09491
09492 if (option_verbose > 2)
09493 ast_verbose(VERBOSE_PREFIX_3 "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
09494
09495 memset(&leave_options, 0, sizeof(leave_options));
09496 leave_options.record_gain = record_gain;
09497 res = leave_voicemail(chan, mailbox, &leave_options);
09498 if (!res)
09499 res = 't';
09500 ast_config_destroy(msg_cfg);
09501 return res;
09502 } else {
09503
09504 if (option_verbose > 2)
09505 ast_verbose( VERBOSE_PREFIX_3 "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
09506 ast_play_and_wait(chan, "vm-nobox");
09507 res = 't';
09508 ast_config_destroy(msg_cfg);
09509 return res;
09510 }
09511 }
09512 res = 0;
09513
09514 break;
09515 }
09516
09517 #ifndef IMAP_STORAGE
09518 ast_config_destroy(msg_cfg);
09519
09520 if (!res) {
09521 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
09522 vms->heard[msg] = 1;
09523 res = wait_file(chan, vms, vms->fn);
09524 }
09525 #endif
09526 return res;
09527 }
09528
09529 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
09530 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
09531 signed char record_gain, struct vm_state *vms)
09532 {
09533
09534 int res = 0;
09535 int cmd = 0;
09536 int max_attempts = 3;
09537 int attempts = 0;
09538 int recorded = 0;
09539 int message_exists = 0;
09540 signed char zero_gain = 0;
09541 char tempfile[PATH_MAX];
09542 char *acceptdtmf = "#";
09543 char *canceldtmf = "";
09544 int canceleddtmf = 0;
09545
09546
09547
09548
09549 if (duration == NULL) {
09550 ast_log(LOG_WARNING, "Error play_record_review called without duration pointer\n");
09551 return -1;
09552 }
09553
09554 if (!outsidecaller)
09555 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
09556 else
09557 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
09558
09559 cmd = '3';
09560
09561 while ((cmd >= 0) && (cmd != 't')) {
09562 switch (cmd) {
09563 case '1':
09564 if (!message_exists) {
09565
09566 cmd = '3';
09567 break;
09568 } else {
09569
09570 if (option_verbose > 2)
09571 ast_verbose(VERBOSE_PREFIX_3 "Saving message as is\n");
09572 if (!outsidecaller)
09573 ast_filerename(tempfile, recordfile, NULL);
09574 ast_stream_and_wait(chan, "vm-msgsaved", chan->language, "");
09575 if (!outsidecaller) {
09576 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms);
09577 DISPOSE(recordfile, -1);
09578 }
09579 cmd = 't';
09580 return res;
09581 }
09582 case '2':
09583
09584 if (option_verbose > 2)
09585 ast_verbose(VERBOSE_PREFIX_3 "Reviewing the message\n");
09586 cmd = ast_stream_and_wait(chan, tempfile, chan->language, AST_DIGIT_ANY);
09587 break;
09588 case '3':
09589 message_exists = 0;
09590
09591 if (recorded == 1) {
09592 if (option_verbose > 2)
09593 ast_verbose(VERBOSE_PREFIX_3 "Re-recording the message\n");
09594 } else {
09595 if (option_verbose > 2)
09596 ast_verbose(VERBOSE_PREFIX_3 "Recording the message\n");
09597 }
09598 if (recorded && outsidecaller) {
09599 cmd = ast_play_and_wait(chan, INTRO);
09600 cmd = ast_play_and_wait(chan, "beep");
09601 }
09602 recorded = 1;
09603
09604 if (record_gain)
09605 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
09606 if (ast_test_flag(vmu, VM_OPERATOR))
09607 canceldtmf = "0";
09608 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
09609 if (strchr(canceldtmf, cmd)) {
09610
09611 canceleddtmf = 1;
09612 }
09613 if (record_gain)
09614 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
09615 if (cmd == -1) {
09616
09617 if (!outsidecaller) {
09618
09619 ast_filedelete(tempfile, NULL);
09620 }
09621 return cmd;
09622 }
09623 if (cmd == '0') {
09624 break;
09625 } else if (cmd == '*') {
09626 break;
09627 }
09628 #if 0
09629 else if (vmu->review && (*duration < 5)) {
09630
09631 if (option_verbose > 2)
09632 ast_verbose(VERBOSE_PREFIX_3 "Message too short\n");
09633 cmd = ast_play_and_wait(chan, "vm-tooshort");
09634 cmd = ast_filedelete(tempfile, NULL);
09635 break;
09636 }
09637 else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
09638
09639 if (option_verbose > 2)
09640 ast_verbose(VERBOSE_PREFIX_3 "Nothing recorded\n");
09641 cmd = ast_filedelete(tempfile, NULL);
09642 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
09643 if (!cmd)
09644 cmd = ast_play_and_wait(chan, "vm-speakup");
09645 break;
09646 }
09647 #endif
09648 else {
09649
09650 message_exists = 1;
09651 cmd = 0;
09652 }
09653 break;
09654 case '4':
09655 case '5':
09656 case '6':
09657 case '7':
09658 case '8':
09659 case '9':
09660 case '*':
09661 case '#':
09662 cmd = ast_play_and_wait(chan, "vm-sorry");
09663 break;
09664 #if 0
09665
09666
09667 case '*':
09668
09669 cmd = ast_play_and_wait(chan, "vm-deleted");
09670 cmd = ast_filedelete(tempfile, NULL);
09671 if (outsidecaller) {
09672 res = vm_exec(chan, NULL);
09673 return res;
09674 }
09675 else
09676 return 1;
09677 #endif
09678 case '0':
09679 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
09680 cmd = ast_play_and_wait(chan, "vm-sorry");
09681 break;
09682 }
09683 if (message_exists || recorded) {
09684 cmd = ast_play_and_wait(chan, "vm-saveoper");
09685 if (!cmd)
09686 cmd = ast_waitfordigit(chan, 3000);
09687 if (cmd == '1') {
09688 ast_filerename(tempfile, recordfile, NULL);
09689 ast_play_and_wait(chan, "vm-msgsaved");
09690 cmd = '0';
09691 } else {
09692 ast_play_and_wait(chan, "vm-deleted");
09693 DELETE(tempfile, -1, tempfile, vmu);
09694 cmd = '0';
09695 }
09696 }
09697 return cmd;
09698 default:
09699
09700
09701
09702 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
09703 return cmd;
09704 if (message_exists) {
09705 cmd = ast_play_and_wait(chan, "vm-review");
09706 } else {
09707 cmd = ast_play_and_wait(chan, "vm-torerecord");
09708 if (!cmd)
09709 cmd = ast_waitfordigit(chan, 600);
09710 }
09711
09712 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
09713 cmd = ast_play_and_wait(chan, "vm-reachoper");
09714 if (!cmd)
09715 cmd = ast_waitfordigit(chan, 600);
09716 }
09717 #if 0
09718 if (!cmd)
09719 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
09720 #endif
09721 if (!cmd)
09722 cmd = ast_waitfordigit(chan, 6000);
09723 if (!cmd) {
09724 attempts++;
09725 }
09726 if (attempts > max_attempts) {
09727 cmd = 't';
09728 }
09729 }
09730 }
09731 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
09732
09733 ast_filedelete(tempfile, NULL);
09734 }
09735
09736 if (cmd != 't' && outsidecaller)
09737 ast_play_and_wait(chan, "vm-goodbye");
09738
09739 return cmd;
09740 }
09741
09742
09743
09744
09745
09746 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
09747 .load = load_module,
09748 .unload = unload_module,
09749 .reload = reload,
09750 );