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)) ? (vmu->preprocessfmt ? vmu->preprocessfmt : format) : (preprocessfmt ? preprocessfmt : format));
03659 snprintf(newfname, sizeof(newfname), "%s.%s", newtmp, newfmt);
03660 snprintf(tmpcmd, sizeof(tmpcmd), "%s < %s.%s > %s", !ast_strlen_zero(vmu->preprocesscmd) ? vmu->preprocesscmd : preprocesscmd, attach, format, newfname);
03661 exitstatus = ast_safe_system(tmpcmd);
03662 if (option_debug)
03663 ast_log(LOG_DEBUG, "Executed preprocesscmd '%s', exitstatus %i\n", tmpcmd, exitstatus);
03664 if (exitstatus) {
03665 ast_log(LOG_WARNING, "Command %s exited with exitstatus %i\n", tmpcmd, exitstatus);
03666 close(tmpfd);
03667 unlink(fname);
03668 } else {
03669 attach = newtmp;
03670 strncpy(format, newfmt, 5);
03671 close(tmpfd);
03672 }
03673
03674 }
03675 }
03676
03677
03678 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
03679 int soxstatus = 0;
03680
03681 if (vmu->volgain < -.001 || vmu->volgain > .001) {
03682 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
03683 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
03684 tmpfd = mkstemp(newtmp);
03685 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
03686 if (option_debug > 2)
03687 ast_log(LOG_DEBUG, "newtmp: %s\n", newtmp);
03688 if (tmpfd > -1) {
03689 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
03690 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
03691 attach = newtmp;
03692 if (option_debug > 2) {
03693 ast_log(LOG_DEBUG, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
03694 }
03695 } else {
03696 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
03697 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
03698 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
03699 }
03700 }
03701 }
03702 fprintf(p, "--%s" ENDL, bound);
03703 if (strcasecmp(format, "mp3"))
03704 fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL, ctype, format, msgnum + 1, format);
03705 else
03706 fprintf(p, "Content-Type: audio/mpeg; name=\"msg%04d.%s\"" ENDL, msgnum + 1, format);
03707 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
03708 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
03709 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL, msgnum + 1, format);
03710 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
03711 base_encode(fname, p);
03712 fprintf(p, ENDL "--%s--" ENDL "." ENDL, bound);
03713 if (tmpfd > -1) {
03714 if (soxstatus == 0) {
03715 unlink(fname);
03716 }
03717 close(tmpfd);
03718 unlink(newtmp);
03719 }
03720 }
03721 }
03722
03723 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)
03724 {
03725 FILE *p=NULL;
03726 char tmp[80] = "/tmp/astmail-XXXXXX";
03727 char tmp2[256];
03728 char *stringp;
03729
03730 if (vmu && ast_strlen_zero(vmu->email)) {
03731 ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
03732 return(0);
03733 }
03734
03735
03736 format = ast_strdupa(format);
03737 stringp = format;
03738 strsep(&stringp, "|");
03739
03740 if (!strcmp(format, "wav49"))
03741 format = "WAV";
03742 if (option_debug > 2)
03743 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));
03744
03745
03746 if ((p = vm_mkftemp(tmp)) == NULL) {
03747 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03748 return -1;
03749 } else {
03750 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, format, duration, attach_user_voicemail, chan, category, 0);
03751 fclose(p);
03752 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03753 ast_safe_system(tmp2);
03754 if (option_debug > 2)
03755 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
03756 }
03757 return 0;
03758 }
03759
03760 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)
03761 {
03762 char date[256];
03763 char host[MAXHOSTNAMELEN] = "";
03764 char who[256];
03765 char dur[PATH_MAX];
03766 char tmp[80] = "/tmp/astmail-XXXXXX";
03767 char tmp2[PATH_MAX];
03768 struct tm tm;
03769 FILE *p;
03770
03771 if ((p = vm_mkftemp(tmp)) == NULL) {
03772 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03773 return -1;
03774 } else {
03775 gethostname(host, sizeof(host)-1);
03776 if (strchr(srcemail, '@'))
03777 ast_copy_string(who, srcemail, sizeof(who));
03778 else {
03779 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03780 }
03781 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03782 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03783 fprintf(p, "Date: %s\n", date);
03784
03785 if (*pagerfromstring) {
03786 struct ast_channel *ast;
03787 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03788 char *passdata;
03789 int vmlen = strlen(fromstring)*3 + 200;
03790 if ((passdata = alloca(vmlen))) {
03791 memset(passdata, 0, vmlen);
03792 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03793 pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
03794 fprintf(p, "From: %s <%s>\n", passdata, who);
03795 } else
03796 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03797 ast_channel_free(ast);
03798 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03799 } else
03800 fprintf(p, "From: Asterisk PBX <%s>\n", who);
03801 fprintf(p, "To: %s\n", pager);
03802 if (pagersubject) {
03803 struct ast_channel *ast;
03804 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03805 char *passdata;
03806 int vmlen = strlen(pagersubject) * 3 + 200;
03807 if ((passdata = alloca(vmlen))) {
03808 memset(passdata, 0, vmlen);
03809 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03810 pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
03811 fprintf(p, "Subject: %s\n\n", passdata);
03812 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03813 ast_channel_free(ast);
03814 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03815 } else
03816 fprintf(p, "Subject: New VM\n\n");
03817 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
03818 if (pagerbody) {
03819 struct ast_channel *ast;
03820 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03821 char *passdata;
03822 int vmlen = strlen(pagerbody)*3 + 200;
03823 if ((passdata = alloca(vmlen))) {
03824 memset(passdata, 0, vmlen);
03825 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03826 pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
03827 fprintf(p, "%s\n", passdata);
03828 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03829 ast_channel_free(ast);
03830 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03831 } else {
03832 fprintf(p, "New %s long msg in box %s\n"
03833 "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
03834 }
03835 fclose(p);
03836 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03837 ast_safe_system(tmp2);
03838 if (option_debug > 2)
03839 ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd);
03840 }
03841 return 0;
03842 }
03843
03844 static int get_date(char *s, int len)
03845 {
03846 struct tm tm;
03847 time_t t;
03848
03849 time(&t);
03850
03851 ast_localtime(&t, &tm, NULL);
03852
03853 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
03854 }
03855
03856 static int play_greeting(struct ast_channel *chan, struct ast_vm_user *vmu, char *filename, char *ecodes)
03857 {
03858 int res = -2;
03859
03860 #ifdef ODBC_STORAGE
03861 int success =
03862 #endif
03863 RETRIEVE(filename, -1, vmu);
03864 if (ast_fileexists(filename, NULL, NULL) > 0) {
03865 res = ast_streamfile(chan, filename, chan->language);
03866 if (res > -1)
03867 res = ast_waitstream(chan, ecodes);
03868 #ifdef ODBC_STORAGE
03869 if (success == -1) {
03870
03871 if (option_debug)
03872 ast_log(LOG_DEBUG, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
03873 store_file(filename, vmu->mailbox, vmu->context, -1);
03874 }
03875 #endif
03876 }
03877 DISPOSE(filename, -1);
03878
03879 return res;
03880 }
03881
03882 static int invent_message(struct ast_channel *chan, struct ast_vm_user *vmu, char *ext, int busy, char *ecodes)
03883 {
03884 int res;
03885 char fn[PATH_MAX];
03886 char dest[PATH_MAX];
03887
03888 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, ext);
03889
03890 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "greet"))) {
03891 ast_log(LOG_WARNING, "Failed to make directory(%s)\n", fn);
03892 return -1;
03893 }
03894
03895 res = play_greeting(chan, vmu, fn, ecodes);
03896 if (res == -2) {
03897
03898 res = ast_stream_and_wait(chan, "vm-theperson", chan->language, ecodes);
03899 if (res)
03900 return res;
03901 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
03902 }
03903
03904 if (res)
03905 return res;
03906
03907 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", chan->language, ecodes);
03908 return res;
03909 }
03910
03911 static void free_zone(struct vm_zone *z)
03912 {
03913 free(z);
03914 }
03915
03916 #ifdef ODBC_STORAGE
03917
03918 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
03919 {
03920 int x = -1;
03921 int res;
03922 SQLHSTMT stmt;
03923 char sql[PATH_MAX];
03924 char rowdata[20];
03925 char tmp[PATH_MAX] = "";
03926 struct odbc_obj *obj;
03927 char *context;
03928 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
03929
03930 if (newmsgs)
03931 *newmsgs = 0;
03932 if (oldmsgs)
03933 *oldmsgs = 0;
03934
03935
03936 if (ast_strlen_zero(mailbox))
03937 return 0;
03938
03939 ast_copy_string(tmp, mailbox, sizeof(tmp));
03940
03941 context = strchr(tmp, '@');
03942 if (context) {
03943 *context = '\0';
03944 context++;
03945 } else
03946 context = "default";
03947
03948 obj = ast_odbc_request_obj(odbc_database, 0);
03949 if (obj) {
03950 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
03951 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03952 if (!stmt) {
03953 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03954 ast_odbc_release_obj(obj);
03955 goto yuck;
03956 }
03957 res = SQLFetch(stmt);
03958 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03959 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03960 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03961 ast_odbc_release_obj(obj);
03962 goto yuck;
03963 }
03964 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03965 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03966 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03967 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03968 ast_odbc_release_obj(obj);
03969 goto yuck;
03970 }
03971 *newmsgs = atoi(rowdata);
03972 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03973
03974 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
03975 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03976 if (!stmt) {
03977 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03978 ast_odbc_release_obj(obj);
03979 goto yuck;
03980 }
03981 res = SQLFetch(stmt);
03982 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03983 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03984 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03985 ast_odbc_release_obj(obj);
03986 goto yuck;
03987 }
03988 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03989 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03990 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03991 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03992 ast_odbc_release_obj(obj);
03993 goto yuck;
03994 }
03995 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03996 ast_odbc_release_obj(obj);
03997 *oldmsgs = atoi(rowdata);
03998 x = 0;
03999 } else
04000 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04001
04002 yuck:
04003 return x;
04004 }
04005
04006 static int messagecount(const char *context, const char *mailbox, const char *folder)
04007 {
04008 struct odbc_obj *obj = NULL;
04009 int nummsgs = 0;
04010 int res;
04011 SQLHSTMT stmt = NULL;
04012 char sql[PATH_MAX];
04013 char rowdata[20];
04014 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04015 if (!folder)
04016 folder = "INBOX";
04017
04018 if (ast_strlen_zero(mailbox))
04019 return 0;
04020
04021 obj = ast_odbc_request_obj(odbc_database, 0);
04022 if (obj) {
04023 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
04024 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04025 if (!stmt) {
04026 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04027 goto yuck;
04028 }
04029 res = SQLFetch(stmt);
04030 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04031 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04032 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04033 goto yuck;
04034 }
04035 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04036 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04037 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04038 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04039 goto yuck;
04040 }
04041 nummsgs = atoi(rowdata);
04042 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04043 } else
04044 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04045
04046 yuck:
04047 if (obj)
04048 ast_odbc_release_obj(obj);
04049 return nummsgs;
04050 }
04051
04052 static int has_voicemail(const char *mailbox, const char *folder)
04053 {
04054 char tmp[256], *tmp2 = tmp, *mbox, *context;
04055 ast_copy_string(tmp, mailbox, sizeof(tmp));
04056 while ((context = mbox = strsep(&tmp2, ","))) {
04057 strsep(&context, "@");
04058 if (ast_strlen_zero(context))
04059 context = "default";
04060 if (messagecount(context, mbox, folder))
04061 return 1;
04062 }
04063 return 0;
04064 }
04065 #endif
04066 #ifndef IMAP_STORAGE
04067
04068 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)
04069 {
04070 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
04071 const char *frombox = mbox(imbox);
04072 int recipmsgnum;
04073 int res = 0;
04074
04075 ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
04076
04077 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04078
04079 if (!dir)
04080 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
04081 else
04082 ast_copy_string(fromdir, dir, sizeof(fromdir));
04083
04084 make_file(frompath, sizeof(frompath), fromdir, msgnum);
04085
04086 if (vm_lock_path(todir))
04087 return ERROR_LOCK_PATH;
04088
04089 recipmsgnum = 0;
04090 do {
04091 make_file(topath, sizeof(topath), todir, recipmsgnum);
04092 if (!EXISTS(todir, recipmsgnum, topath, chan->language))
04093 break;
04094 recipmsgnum++;
04095 } while (recipmsgnum < recip->maxmsg);
04096 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
04097 #ifndef ODBC_STORAGE
04098 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
04099 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
04100 } else {
04101 #endif
04102
04103
04104
04105 copy_plain_file(frompath, topath);
04106 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL);
04107 vm_delete(topath);
04108 #ifndef ODBC_STORAGE
04109 }
04110 #endif
04111 } else {
04112 ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
04113 res = -1;
04114 }
04115 ast_unlock_path(todir);
04116 notify_new_message(chan, recip, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
04117
04118 return res;
04119 }
04120 #endif
04121 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
04122 static int messagecount(const char *context, const char *mailbox, const char *folder)
04123 {
04124 return __has_voicemail(context, mailbox, folder, 0);
04125 }
04126
04127
04128 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
04129 {
04130 DIR *dir;
04131 struct dirent *de;
04132 char fn[256];
04133 int ret = 0;
04134 if (!folder)
04135 folder = "INBOX";
04136
04137 if (ast_strlen_zero(mailbox))
04138 return 0;
04139 if (!context)
04140 context = "default";
04141 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
04142 dir = opendir(fn);
04143 if (!dir)
04144 return 0;
04145 while ((de = readdir(dir))) {
04146 if (!strncasecmp(de->d_name, "msg", 3)) {
04147 if (shortcircuit) {
04148 ret = 1;
04149 break;
04150 } else if (!strncasecmp(de->d_name + 8, "txt", 3))
04151 ret++;
04152 }
04153 }
04154 closedir(dir);
04155 return ret;
04156 }
04157
04158
04159 static int has_voicemail(const char *mailbox, const char *folder)
04160 {
04161 char tmp[256], *tmp2 = tmp, *mbox, *context;
04162 ast_copy_string(tmp, mailbox, sizeof(tmp));
04163 while ((mbox = strsep(&tmp2, ","))) {
04164 if ((context = strchr(mbox, '@')))
04165 *context++ = '\0';
04166 else
04167 context = "default";
04168 if (__has_voicemail(context, mbox, folder, 1))
04169 return 1;
04170 }
04171 return 0;
04172 }
04173
04174
04175 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
04176 {
04177 char tmp[256];
04178 char *context;
04179
04180 if (newmsgs)
04181 *newmsgs = 0;
04182 if (oldmsgs)
04183 *oldmsgs = 0;
04184
04185 if (ast_strlen_zero(mailbox))
04186 return 0;
04187 if (strchr(mailbox, ',')) {
04188 int tmpnew, tmpold;
04189 char *mb, *cur;
04190
04191 ast_copy_string(tmp, mailbox, sizeof(tmp));
04192 mb = tmp;
04193 while ((cur = strsep(&mb, ", "))) {
04194 if (!ast_strlen_zero(cur)) {
04195 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
04196 return -1;
04197 else {
04198 if (newmsgs)
04199 *newmsgs += tmpnew;
04200 if (oldmsgs)
04201 *oldmsgs += tmpold;
04202 }
04203 }
04204 }
04205 return 0;
04206 }
04207 ast_copy_string(tmp, mailbox, sizeof(tmp));
04208 context = strchr(tmp, '@');
04209 if (context) {
04210 *context = '\0';
04211 context++;
04212 } else
04213 context = "default";
04214 if (newmsgs)
04215 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
04216 if (oldmsgs)
04217 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
04218 return 0;
04219 }
04220
04221 #endif
04222
04223 static void run_externnotify(char *context, char *extension)
04224 {
04225 char arguments[255];
04226 char ext_context[256] = "";
04227 int newvoicemails = 0, oldvoicemails = 0;
04228 struct ast_smdi_mwi_message *mwi_msg;
04229
04230 if (!ast_strlen_zero(context))
04231 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
04232 else
04233 ast_copy_string(ext_context, extension, sizeof(ext_context));
04234
04235 if (!strcasecmp(externnotify, "smdi")) {
04236 if (ast_app_has_voicemail(ext_context, NULL))
04237 ast_smdi_mwi_set(smdi_iface, extension);
04238 else
04239 ast_smdi_mwi_unset(smdi_iface, extension);
04240
04241 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
04242 ast_log(LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
04243 if (!strncmp(mwi_msg->cause, "INV", 3))
04244 ast_log(LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
04245 else if (!strncmp(mwi_msg->cause, "BLK", 3))
04246 ast_log(LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
04247 ast_log(LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
04248 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
04249 } else {
04250 if (option_debug)
04251 ast_log(LOG_DEBUG, "Successfully executed SMDI MWI change for %s\n", extension);
04252 }
04253 } else if (!ast_strlen_zero(externnotify)) {
04254 if (inboxcount(ext_context, &newvoicemails, &oldvoicemails)) {
04255 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
04256 } else {
04257 snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
04258 if (option_debug)
04259 ast_log(LOG_DEBUG, "Executing %s\n", arguments);
04260 ast_safe_system(arguments);
04261 }
04262 }
04263 }
04264
04265 struct leave_vm_options {
04266 unsigned int flags;
04267 signed char record_gain;
04268 };
04269
04270 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
04271 {
04272 #ifdef IMAP_STORAGE
04273 int newmsgs, oldmsgs;
04274 #endif
04275 struct vm_state *vms = NULL;
04276 char txtfile[PATH_MAX], tmptxtfile[PATH_MAX];
04277 char callerid[256];
04278 FILE *txt;
04279 char date[50];
04280 int txtdes;
04281 int res = 0;
04282 int msgnum;
04283 int duration = 0;
04284 int ausemacro = 0;
04285 int ousemacro = 0;
04286 int ouseexten = 0;
04287 char dir[PATH_MAX], tmpdir[PATH_MAX];
04288 char dest[PATH_MAX];
04289 char fn[PATH_MAX];
04290 char prefile[PATH_MAX] = "";
04291 char tempfile[PATH_MAX] = "";
04292 char ext_context[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2] = "";
04293 char fmt[80];
04294 char *context;
04295 char ecodes[16] = "#";
04296 char tmp[1324] = "", *tmpptr;
04297 struct ast_vm_user *vmu;
04298 struct ast_vm_user svm;
04299 const char *category = NULL;
04300
04301 if (strlen(ext) > sizeof(tmp) - 1) {
04302 ast_log(LOG_WARNING, "List of extensions is too long (>%ld). Truncating.\n", (long) sizeof(tmp) - 1);
04303 }
04304 ast_copy_string(tmp, ext, sizeof(tmp));
04305 ext = tmp;
04306 context = strchr(tmp, '@');
04307 if (context) {
04308 *context++ = '\0';
04309 tmpptr = strchr(context, '&');
04310 } else {
04311 tmpptr = strchr(ext, '&');
04312 }
04313
04314 if (tmpptr)
04315 *tmpptr++ = '\0';
04316
04317 category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
04318
04319 if (option_debug > 2)
04320 ast_log(LOG_DEBUG, "Before find_user\n");
04321 if (!(vmu = find_user(&svm, context, ext))) {
04322 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
04323 if (ast_test_flag(options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
04324 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
04325 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04326 return res;
04327 }
04328
04329 if (strcmp(vmu->context, "default"))
04330 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
04331 else
04332 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
04333 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
04334 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "busy");
04335 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
04336 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
04337 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "unavail");
04338 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
04339 }
04340 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
04341 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "temp"))) {
04342 ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
04343 return -1;
04344 }
04345 RETRIEVE(tempfile, -1, vmu);
04346 if (ast_fileexists(tempfile, NULL, NULL) > 0)
04347 ast_copy_string(prefile, tempfile, sizeof(prefile));
04348 DISPOSE(tempfile, -1);
04349
04350 #ifndef IMAP_STORAGE
04351 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
04352 #else
04353 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
04354 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
04355 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
04356 }
04357 #endif
04358 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp");
04359
04360
04361 if (ast_test_flag(vmu, VM_OPERATOR)) {
04362 if (!ast_strlen_zero(vmu->exit)) {
04363 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
04364 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04365 ouseexten = 1;
04366 }
04367 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
04368 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04369 ouseexten = 1;
04370 }
04371 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
04372 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04373 ousemacro = 1;
04374 }
04375 }
04376
04377 if (!ast_strlen_zero(vmu->exit)) {
04378 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
04379 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04380 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
04381 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04382 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
04383 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04384 ausemacro = 1;
04385 }
04386
04387
04388 if (!ast_strlen_zero(prefile)) {
04389 res = play_greeting(chan, vmu, prefile, ecodes);
04390 if (res == -2) {
04391
04392 if (option_debug)
04393 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
04394 res = invent_message(chan, vmu, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
04395 }
04396 if (res < 0) {
04397 if (option_debug)
04398 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
04399 free_user(vmu);
04400 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04401 return -1;
04402 }
04403 }
04404 if (res == '#') {
04405
04406 ast_set_flag(options, OPT_SILENT);
04407 res = 0;
04408 }
04409 if (!res && !ast_test_flag(options, OPT_SILENT)) {
04410 res = ast_stream_and_wait(chan, INTRO, chan->language, ecodes);
04411 if (res == '#') {
04412 ast_set_flag(options, OPT_SILENT);
04413 res = 0;
04414 }
04415 }
04416 if (res > 0)
04417 ast_stopstream(chan);
04418
04419
04420 if (res == '*') {
04421 chan->exten[0] = 'a';
04422 chan->exten[1] = '\0';
04423 if (!ast_strlen_zero(vmu->exit)) {
04424 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
04425 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
04426 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
04427 }
04428 chan->priority = 0;
04429 free_user(vmu);
04430 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
04431 return 0;
04432 }
04433
04434
04435 if (res == '0') {
04436 transfer:
04437 if (ouseexten || ousemacro) {
04438 chan->exten[0] = 'o';
04439 chan->exten[1] = '\0';
04440 if (!ast_strlen_zero(vmu->exit)) {
04441 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
04442 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
04443 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
04444 }
04445 ast_play_and_wait(chan, "transfer");
04446 chan->priority = 0;
04447 free_user(vmu);
04448 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
04449 }
04450 return OPERATOR_EXIT;
04451 }
04452 if (res < 0) {
04453 free_user(vmu);
04454 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04455 return -1;
04456 }
04457
04458 ast_copy_string(fmt, vmfmts, sizeof(fmt));
04459 if (!ast_strlen_zero(fmt)) {
04460 msgnum = 0;
04461
04462 #ifdef IMAP_STORAGE
04463
04464
04465 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
04466 if (res < 0) {
04467 ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
04468 return -1;
04469 }
04470 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
04471
04472
04473 if (!(vms = create_vm_state_from_user(vmu))) {
04474 ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
04475 return -1;
04476 }
04477 }
04478 vms->newmessages++;
04479
04480 msgnum = newmsgs + oldmsgs;
04481 if (option_debug > 2)
04482 ast_log(LOG_DEBUG, "Messagecount set to %d\n",msgnum);
04483 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
04484
04485 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
04486
04487 if (imap_check_limits(chan, vms, vmu, msgnum)) {
04488 goto leave_vm_out;
04489 }
04490 #else
04491 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
04492 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
04493 if (!res)
04494 res = ast_waitstream(chan, "");
04495 ast_log(LOG_WARNING, "No more messages possible\n");
04496 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04497 inprocess_count(vmu->mailbox, vmu->context, -1);
04498 goto leave_vm_out;
04499 }
04500
04501 #endif
04502 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
04503 txtdes = mkstemp(tmptxtfile);
04504 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
04505 if (txtdes < 0) {
04506 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
04507 if (!res)
04508 res = ast_waitstream(chan, "");
04509 ast_log(LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
04510 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04511 inprocess_count(vmu->mailbox, vmu->context, -1);
04512 goto leave_vm_out;
04513 }
04514
04515
04516 if (res >= 0) {
04517
04518 res = ast_stream_and_wait(chan, "beep", chan->language, "");
04519 }
04520
04521
04522 txt = fdopen(txtdes, "w+");
04523 if (txt) {
04524 get_date(date, sizeof(date));
04525 fprintf(txt,
04526 ";\n"
04527 "; Message Information file\n"
04528 ";\n"
04529 "[message]\n"
04530 "origmailbox=%s\n"
04531 "context=%s\n"
04532 "macrocontext=%s\n"
04533 "exten=%s\n"
04534 "priority=%d\n"
04535 "callerchan=%s\n"
04536 "callerid=%s\n"
04537 "origdate=%s\n"
04538 "origtime=%ld\n"
04539 "category=%s\n",
04540 ext,
04541 chan->context,
04542 chan->macrocontext,
04543 chan->exten,
04544 chan->priority,
04545 chan->name,
04546 ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"),
04547 date, (long)time(NULL),
04548 category ? category : "");
04549 } else
04550 ast_log(LOG_WARNING, "Error opening text file for output\n");
04551 res = play_record_review(chan, NULL, tmptxtfile, vmmaxmessage, fmt, 1, vmu, &duration, NULL, options->record_gain, vms);
04552
04553 if (txt) {
04554 if (duration < vmminmessage) {
04555 fclose(txt);
04556 if (option_verbose > 2)
04557 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
04558 ast_filedelete(tmptxtfile, NULL);
04559 unlink(tmptxtfile);
04560 inprocess_count(vmu->mailbox, vmu->context, -1);
04561 } else {
04562 fprintf(txt, "duration=%d\n", duration);
04563 fclose(txt);
04564 if (vm_lock_path(dir)) {
04565 ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
04566
04567 ast_filedelete(tmptxtfile, NULL);
04568 unlink(tmptxtfile);
04569 inprocess_count(vmu->mailbox, vmu->context, -1);
04570 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
04571 if (option_debug)
04572 ast_log(LOG_DEBUG, "The recorded media file is gone, so we should remove the .txt file too!\n");
04573 unlink(tmptxtfile);
04574 ast_unlock_path(dir);
04575 inprocess_count(vmu->mailbox, vmu->context, -1);
04576 } else {
04577 #ifndef IMAP_STORAGE
04578 msgnum = last_message_index(vmu, dir) + 1;
04579 #endif
04580 make_file(fn, sizeof(fn), dir, msgnum);
04581
04582
04583 #ifndef IMAP_STORAGE
04584 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
04585 #else
04586 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
04587 #endif
04588
04589 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
04590 ast_filerename(tmptxtfile, fn, NULL);
04591 rename(tmptxtfile, txtfile);
04592 inprocess_count(vmu->mailbox, vmu->context, -1);
04593
04594 ast_unlock_path(dir);
04595
04596
04597
04598 if (ast_fileexists(fn, NULL, NULL) > 0) {
04599 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms);
04600 }
04601
04602
04603 while (tmpptr) {
04604 struct ast_vm_user recipu, *recip;
04605 char *exten, *context;
04606
04607 exten = strsep(&tmpptr, "&");
04608 context = strchr(exten, '@');
04609 if (context) {
04610 *context = '\0';
04611 context++;
04612 }
04613 if ((recip = find_user(&recipu, context, exten))) {
04614 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir);
04615 free_user(recip);
04616 }
04617 }
04618
04619 if (ast_fileexists(fn, NULL, NULL)) {
04620 notify_new_message(chan, vmu, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
04621 DISPOSE(dir, msgnum);
04622 }
04623 }
04624 }
04625 } else {
04626 inprocess_count(vmu->mailbox, vmu->context, -1);
04627 }
04628 if (res == '0') {
04629 goto transfer;
04630 } else if (res > 0 && res != 't')
04631 res = 0;
04632
04633 if (duration < vmminmessage)
04634
04635 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04636 else
04637 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
04638 } else
04639 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
04640 leave_vm_out:
04641 free_user(vmu);
04642
04643 return res;
04644 }
04645
04646 #if !defined(IMAP_STORAGE)
04647 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
04648 {
04649
04650
04651 int x,dest;
04652 char sfn[PATH_MAX];
04653 char dfn[PATH_MAX];
04654
04655 if (vm_lock_path(dir))
04656 return ERROR_LOCK_PATH;
04657
04658 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
04659 make_file(sfn, sizeof(sfn), dir, x);
04660 if (EXISTS(dir, x, sfn, NULL)) {
04661
04662 if (x != dest) {
04663 make_file(dfn, sizeof(dfn), dir, dest);
04664 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
04665 }
04666
04667 dest++;
04668 }
04669 }
04670 ast_unlock_path(dir);
04671
04672 return dest;
04673 }
04674 #endif
04675
04676 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
04677 {
04678 int d;
04679 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, (char *) NULL);
04680 return d;
04681 }
04682
04683 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
04684 {
04685 #ifdef IMAP_STORAGE
04686
04687
04688 char sequence[10];
04689
04690 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
04691 if (option_debug > 2)
04692 ast_log(LOG_DEBUG, "Copying sequence %s to mailbox %s\n",sequence,(char *) mbox(box));
04693 ast_mutex_lock(&vms->lock);
04694 if (box == 1) {
04695 mail_setflag(vms->mailstream, sequence, "\\Seen");
04696 } else if (box == 0) {
04697 mail_clearflag(vms->mailstream, sequence, "\\Seen");
04698 }
04699 if (!strcasecmp(mbox(0), vms->curbox) && (box == 0 || box == 1)) {
04700 ast_mutex_unlock(&vms->lock);
04701 return 0;
04702 } else {
04703 int res = !mail_copy(vms->mailstream,sequence,(char *) mbox(box));
04704 ast_mutex_unlock(&vms->lock);
04705 return res;
04706 }
04707 #else
04708 char *dir = vms->curdir;
04709 char *username = vms->username;
04710 char *context = vmu->context;
04711 char sfn[PATH_MAX];
04712 char dfn[PATH_MAX];
04713 char ddir[PATH_MAX];
04714 const char *dbox = mbox(box);
04715 int x;
04716 make_file(sfn, sizeof(sfn), dir, msg);
04717 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
04718
04719 if (vm_lock_path(ddir))
04720 return ERROR_LOCK_PATH;
04721
04722 for (x = 0; x < vmu->maxmsg; x++) {
04723 make_file(dfn, sizeof(dfn), ddir, x);
04724 if (!EXISTS(ddir, x, dfn, NULL))
04725 break;
04726 }
04727 if (x >= vmu->maxmsg) {
04728 ast_unlock_path(ddir);
04729 return ERROR_MAILBOX_FULL;
04730 }
04731 if (strcmp(sfn, dfn)) {
04732 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
04733 }
04734 ast_unlock_path(ddir);
04735 #endif
04736 return 0;
04737 }
04738
04739 static int adsi_logo(unsigned char *buf)
04740 {
04741 int bytes = 0;
04742 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
04743 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
04744 return bytes;
04745 }
04746
04747 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
04748 {
04749 unsigned char buf[256];
04750 int bytes=0;
04751 int x;
04752 char num[5];
04753
04754 *useadsi = 0;
04755 bytes += ast_adsi_data_mode(buf + bytes);
04756 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04757
04758 bytes = 0;
04759 bytes += adsi_logo(buf);
04760 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04761 #ifdef DISPLAY
04762 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
04763 #endif
04764 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04765 bytes += ast_adsi_data_mode(buf + bytes);
04766 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04767
04768 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
04769 bytes = 0;
04770 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
04771 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04772 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04773 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04774 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04775 return 0;
04776 }
04777
04778 #ifdef DISPLAY
04779
04780 bytes = 0;
04781 bytes += ast_adsi_logo(buf);
04782 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04783 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
04784 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04785 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04786 #endif
04787 bytes = 0;
04788 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
04789 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
04790 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
04791 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
04792 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
04793 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
04794 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04795
04796 #ifdef DISPLAY
04797
04798 bytes = 0;
04799 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
04800 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04801
04802 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04803 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04804 #endif
04805
04806 bytes = 0;
04807
04808 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
04809 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
04810 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
04811 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
04812 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
04813 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
04814 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04815
04816 #ifdef DISPLAY
04817
04818 bytes = 0;
04819 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
04820 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04821 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04822 #endif
04823
04824 bytes = 0;
04825 for (x=0;x<5;x++) {
04826 snprintf(num, sizeof(num), "%d", x);
04827 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
04828 }
04829 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
04830 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04831
04832 #ifdef DISPLAY
04833
04834 bytes = 0;
04835 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
04836 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04837 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04838 #endif
04839
04840 if (ast_adsi_end_download(chan)) {
04841 bytes = 0;
04842 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
04843 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04844 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04845 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04846 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04847 return 0;
04848 }
04849 bytes = 0;
04850 bytes += ast_adsi_download_disconnect(buf + bytes);
04851 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04852 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04853
04854 if (option_debug)
04855 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
04856
04857 #ifdef DISPLAY
04858
04859 bytes = 0;
04860 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
04861 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04862 #endif
04863 if (option_debug)
04864 ast_log(LOG_DEBUG, "Restarting session...\n");
04865
04866 bytes = 0;
04867
04868 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
04869 *useadsi = 1;
04870 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
04871 } else
04872 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
04873
04874 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04875 return 0;
04876 }
04877
04878 static void adsi_begin(struct ast_channel *chan, int *useadsi)
04879 {
04880 int x;
04881 if (!ast_adsi_available(chan))
04882 return;
04883 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
04884 if (x < 0)
04885 return;
04886 if (!x) {
04887 if (adsi_load_vmail(chan, useadsi)) {
04888 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
04889 return;
04890 }
04891 } else
04892 *useadsi = 1;
04893 }
04894
04895 static void adsi_login(struct ast_channel *chan)
04896 {
04897 unsigned char buf[256];
04898 int bytes=0;
04899 unsigned char keys[8];
04900 int x;
04901 if (!ast_adsi_available(chan))
04902 return;
04903
04904 for (x=0;x<8;x++)
04905 keys[x] = 0;
04906
04907 keys[3] = ADSI_KEY_APPS + 3;
04908
04909 bytes += adsi_logo(buf + bytes);
04910 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
04911 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
04912 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04913 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
04914 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
04915 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
04916 bytes += ast_adsi_set_keys(buf + bytes, keys);
04917 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04918 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04919 }
04920
04921 static void adsi_password(struct ast_channel *chan)
04922 {
04923 unsigned char buf[256];
04924 int bytes=0;
04925 unsigned char keys[8];
04926 int x;
04927 if (!ast_adsi_available(chan))
04928 return;
04929
04930 for (x=0;x<8;x++)
04931 keys[x] = 0;
04932
04933 keys[3] = ADSI_KEY_APPS + 3;
04934
04935 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04936 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
04937 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
04938 bytes += ast_adsi_set_keys(buf + bytes, keys);
04939 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04940 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04941 }
04942
04943 static void adsi_folders(struct ast_channel *chan, int start, char *label)
04944 {
04945 unsigned char buf[256];
04946 int bytes=0;
04947 unsigned char keys[8];
04948 int x,y;
04949
04950 if (!ast_adsi_available(chan))
04951 return;
04952
04953 for (x=0;x<5;x++) {
04954 y = ADSI_KEY_APPS + 12 + start + x;
04955 if (y > ADSI_KEY_APPS + 12 + 4)
04956 y = 0;
04957 keys[x] = ADSI_KEY_SKT | y;
04958 }
04959 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
04960 keys[6] = 0;
04961 keys[7] = 0;
04962
04963 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
04964 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
04965 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04966 bytes += ast_adsi_set_keys(buf + bytes, keys);
04967 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04968
04969 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04970 }
04971
04972 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
04973 {
04974 int bytes=0;
04975 unsigned char buf[256];
04976 char buf1[256], buf2[256];
04977 char fn2[PATH_MAX];
04978
04979 char cid[256]="";
04980 char *val;
04981 char *name, *num;
04982 char datetime[21]="";
04983 FILE *f;
04984
04985 unsigned char keys[8];
04986
04987 int x;
04988
04989 if (!ast_adsi_available(chan))
04990 return;
04991
04992
04993 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
04994 f = fopen(fn2, "r");
04995 if (f) {
04996 while (!feof(f)) {
04997 if (!fgets((char *)buf, sizeof(buf), f)) {
04998 continue;
04999 }
05000 if (!feof(f)) {
05001 char *stringp=NULL;
05002 stringp = (char *)buf;
05003 strsep(&stringp, "=");
05004 val = strsep(&stringp, "=");
05005 if (!ast_strlen_zero(val)) {
05006 if (!strcmp((char *)buf, "callerid"))
05007 ast_copy_string(cid, val, sizeof(cid));
05008 if (!strcmp((char *)buf, "origdate"))
05009 ast_copy_string(datetime, val, sizeof(datetime));
05010 }
05011 }
05012 }
05013 fclose(f);
05014 }
05015
05016 for (x=0;x<5;x++)
05017 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05018 keys[6] = 0x0;
05019 keys[7] = 0x0;
05020
05021 if (!vms->curmsg) {
05022
05023 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05024 }
05025 if (vms->curmsg >= vms->lastmsg) {
05026
05027 if (vms->curmsg) {
05028
05029 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05030 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05031
05032 } else {
05033
05034 keys[3] = 1;
05035 }
05036 }
05037
05038 if (!ast_strlen_zero(cid)) {
05039 ast_callerid_parse(cid, &name, &num);
05040 if (!name)
05041 name = num;
05042 } else
05043 name = "Unknown Caller";
05044
05045
05046
05047 if (vms->deleted[vms->curmsg])
05048 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05049
05050
05051 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05052 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
05053 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
05054 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
05055
05056 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05057 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05058 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
05059 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
05060 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05061 bytes += ast_adsi_set_keys(buf + bytes, keys);
05062 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05063
05064 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05065 }
05066
05067 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
05068 {
05069 int bytes=0;
05070 unsigned char buf[256];
05071 unsigned char keys[8];
05072
05073 int x;
05074
05075 if (!ast_adsi_available(chan))
05076 return;
05077
05078
05079 for (x=0;x<5;x++)
05080 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05081
05082 keys[6] = 0x0;
05083 keys[7] = 0x0;
05084
05085 if (!vms->curmsg) {
05086
05087 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05088 }
05089 if (vms->curmsg >= vms->lastmsg) {
05090
05091 if (vms->curmsg) {
05092
05093 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05094 } else {
05095
05096 keys[3] = 1;
05097 }
05098 }
05099
05100
05101 if (vms->deleted[vms->curmsg])
05102 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05103
05104
05105 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05106 bytes += ast_adsi_set_keys(buf + bytes, keys);
05107 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05108
05109 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05110 }
05111
05112 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
05113 {
05114 unsigned char buf[256] = "";
05115 char buf1[256] = "", buf2[256] = "";
05116 int bytes=0;
05117 unsigned char keys[8];
05118 int x;
05119
05120 char *newm = (vms->newmessages == 1) ? "message" : "messages";
05121 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
05122 if (!ast_adsi_available(chan))
05123 return;
05124 if (vms->newmessages) {
05125 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
05126 if (vms->oldmessages) {
05127 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
05128 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
05129 } else {
05130 snprintf(buf2, sizeof(buf2), "%s.", newm);
05131 }
05132 } else if (vms->oldmessages) {
05133 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
05134 snprintf(buf2, sizeof(buf2), "%s.", oldm);
05135 } else {
05136 strcpy(buf1, "You have no messages.");
05137 buf2[0] = ' ';
05138 buf2[1] = '\0';
05139 }
05140 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05141 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05142 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05143
05144 for (x=0;x<6;x++)
05145 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
05146 keys[6] = 0;
05147 keys[7] = 0;
05148
05149
05150 if (vms->lastmsg < 0)
05151 keys[0] = 1;
05152 bytes += ast_adsi_set_keys(buf + bytes, keys);
05153
05154 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05155
05156 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05157 }
05158
05159 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
05160 {
05161 unsigned char buf[256] = "";
05162 char buf1[256] = "", buf2[256] = "";
05163 int bytes=0;
05164 unsigned char keys[8];
05165 int x;
05166
05167 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
05168
05169 if (!ast_adsi_available(chan))
05170 return;
05171
05172
05173 for (x=0;x<6;x++)
05174 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
05175
05176 keys[6] = 0;
05177 keys[7] = 0;
05178
05179 if ((vms->lastmsg + 1) < 1)
05180 keys[0] = 0;
05181
05182 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
05183 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
05184
05185 if (vms->lastmsg + 1)
05186 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
05187 else
05188 strcpy(buf2, "no messages.");
05189 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05190 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05191 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
05192 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05193 bytes += ast_adsi_set_keys(buf + bytes, keys);
05194
05195 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05196
05197 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05198
05199 }
05200
05201
05202
05203
05204
05205
05206
05207
05208
05209
05210
05211
05212
05213
05214
05215 static void adsi_goodbye(struct ast_channel *chan)
05216 {
05217 unsigned char buf[256];
05218 int bytes=0;
05219
05220 if (!ast_adsi_available(chan))
05221 return;
05222 bytes += adsi_logo(buf + bytes);
05223 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
05224 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
05225 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05226 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05227
05228 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05229 }
05230
05231
05232
05233
05234
05235 static int get_folder(struct ast_channel *chan, int start)
05236 {
05237 int x;
05238 int d;
05239 char fn[PATH_MAX];
05240 d = ast_play_and_wait(chan, "vm-press");
05241 if (d)
05242 return d;
05243 for (x = start; x< 5; x++) {
05244 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL)))
05245 return d;
05246 d = ast_play_and_wait(chan, "vm-for");
05247 if (d)
05248 return d;
05249 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
05250 d = vm_play_folder_name(chan, fn);
05251 if (d)
05252 return d;
05253 d = ast_waitfordigit(chan, 500);
05254 if (d)
05255 return d;
05256 }
05257 d = ast_play_and_wait(chan, "vm-tocancel");
05258 if (d)
05259 return d;
05260 d = ast_waitfordigit(chan, 4000);
05261 return d;
05262 }
05263
05264 static int get_folder2(struct ast_channel *chan, char *fn, int start)
05265 {
05266 int res = 0;
05267 int loops = 0;
05268 res = ast_play_and_wait(chan, fn);
05269 while (((res < '0') || (res > '9')) &&
05270 (res != '#') && (res >= 0) &&
05271 loops < 4) {
05272 res = get_folder(chan, 0);
05273 loops++;
05274 }
05275 if (loops == 4) {
05276 return '#';
05277 }
05278 return res;
05279 }
05280
05281 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfmts,
05282 char *context, signed char record_gain, long *duration, struct vm_state *vms)
05283 {
05284 int cmd = 0;
05285 int retries = 0, prepend_duration = 0, already_recorded = 0;
05286 signed char zero_gain = 0;
05287 struct ast_config *msg_cfg;
05288 const char *duration_cstr;
05289 char msgfile[PATH_MAX], backup[PATH_MAX];
05290 char textfile[PATH_MAX];
05291 char backup_textfile[PATH_MAX];
05292 struct ast_category *msg_cat;
05293 char duration_str[12] = "";
05294
05295 ast_log(LOG_NOTICE, "curdir=%s\n", curdir);
05296
05297 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
05298 strcpy(textfile, msgfile);
05299 strcpy(backup, msgfile);
05300 strcpy(backup_textfile, msgfile);
05301 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
05302 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
05303 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
05304
05305 if (!(msg_cfg = ast_config_load(textfile))) {
05306 return -1;
05307 }
05308
05309 *duration = 0;
05310 if ((duration_cstr = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
05311 *duration = atoi(duration_cstr);
05312 }
05313
05314 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
05315 if (cmd)
05316 retries = 0;
05317 switch (cmd) {
05318 case '1':
05319
05320 {
05321 prepend_duration = 0;
05322
05323
05324 #ifndef IMAP_STORAGE
05325 if (already_recorded) {
05326 ast_filecopy(backup, msgfile, NULL);
05327 copy(textfile, backup_textfile);
05328 } else {
05329 ast_filecopy(msgfile, backup, NULL);
05330 copy(textfile, backup_textfile);
05331 }
05332 #endif
05333 already_recorded = 1;
05334
05335 if (record_gain)
05336 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
05337
05338 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vmfmts, &prepend_duration, 1, silencethreshold, maxsilence);
05339 if (cmd == 'S') {
05340 ast_filerename(backup, msgfile, NULL);
05341 }
05342
05343 if (record_gain)
05344 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
05345
05346 if (prepend_duration) {
05347 prepend_duration += *duration;
05348 }
05349
05350 break;
05351 }
05352 case '2':
05353 cmd = 't';
05354 break;
05355 case '*':
05356 cmd = '*';
05357 break;
05358 default:
05359 cmd = ast_play_and_wait(chan,"vm-forwardoptions");
05360
05361 if (!cmd)
05362 cmd = ast_play_and_wait(chan,"vm-starmain");
05363
05364 if (!cmd)
05365 cmd = ast_waitfordigit(chan,6000);
05366 if (!cmd)
05367 retries++;
05368 if (retries > 3)
05369 cmd = 't';
05370 }
05371 }
05372
05373 if (already_recorded && cmd == -1) {
05374
05375 ast_filerename(backup, msgfile, NULL);
05376 if (duration_cstr) {
05377 ast_copy_string(duration_str, duration_cstr, sizeof(duration_str));
05378 }
05379 } else if (prepend_duration) {
05380 *duration = prepend_duration;
05381 snprintf(duration_str, sizeof(duration_str), "%d", prepend_duration);
05382 }
05383
05384 msg_cat = ast_category_get(msg_cfg, "message");
05385 if (!ast_strlen_zero(duration_str) && !ast_variable_update(msg_cat, "duration", duration_str, NULL, 0)) {
05386 config_text_file_save(textfile, msg_cfg, "app_voicemail");
05387 }
05388 ast_config_destroy(msg_cfg);
05389
05390 if (cmd == 't' || cmd == 'S')
05391 cmd = 0;
05392 return cmd;
05393 }
05394
05395 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname)
05396 {
05397 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
05398 int newmsgs = 0, oldmsgs = 0;
05399 const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
05400
05401 #ifndef IMAP_STORAGE
05402 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
05403 #else
05404 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
05405 #endif
05406 make_file(fn, sizeof(fn), todir, msgnum);
05407 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
05408
05409 if (!ast_strlen_zero(vmu->attachfmt)) {
05410 if (strstr(fmt, vmu->attachfmt)) {
05411 fmt = vmu->attachfmt;
05412 } else {
05413 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);
05414 }
05415 }
05416
05417
05418 fmt = ast_strdupa(fmt);
05419 stringp = fmt;
05420 strsep(&stringp, "|");
05421
05422 if (!ast_strlen_zero(vmu->email)) {
05423 int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
05424 char *myserveremail = serveremail;
05425 attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
05426 if (!ast_strlen_zero(vmu->serveremail))
05427 myserveremail = vmu->serveremail;
05428
05429 if (attach_user_voicemail)
05430 RETRIEVE(todir, msgnum, vmu);
05431
05432
05433 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category);
05434
05435 if (attach_user_voicemail)
05436 DISPOSE(todir, msgnum);
05437 }
05438
05439 if (!ast_strlen_zero(vmu->pager)) {
05440 char *myserveremail = serveremail;
05441 if (!ast_strlen_zero(vmu->serveremail))
05442 myserveremail = vmu->serveremail;
05443 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, duration, vmu, category);
05444 }
05445
05446 if (ast_test_flag(vmu, VM_DELETE)) {
05447 DELETE(todir, msgnum, fn, vmu);
05448 }
05449
05450
05451 if (ast_app_has_voicemail(ext_context, NULL)) {
05452 ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs);
05453 }
05454 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);
05455 run_externnotify(vmu->context, vmu->mailbox);
05456 return 0;
05457 }
05458
05459 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)
05460 {
05461 #ifdef IMAP_STORAGE
05462 int todircount=0;
05463 struct vm_state *dstvms;
05464 #else
05465 char textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
05466 #endif
05467 char username[70]="";
05468 int res = 0, cmd = 0;
05469 struct ast_vm_user *receiver = NULL, *vmtmp;
05470 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
05471 char *stringp;
05472 const char *s;
05473 int saved_messages = 0;
05474 int valid_extensions = 0;
05475 char *dir;
05476 int curmsg;
05477 int prompt_played = 0;
05478
05479 if (vms == NULL) return -1;
05480 dir = vms->curdir;
05481 curmsg = vms->curmsg;
05482
05483 while (!res && !valid_extensions) {
05484 int use_directory = 0;
05485 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
05486 int done = 0;
05487 int retries = 0;
05488 cmd=0;
05489 while ((cmd >= 0) && !done ){
05490 if (cmd)
05491 retries = 0;
05492 switch (cmd) {
05493 case '1':
05494 use_directory = 0;
05495 done = 1;
05496 break;
05497 case '2':
05498 use_directory = 1;
05499 done=1;
05500 break;
05501 case '*':
05502 cmd = 't';
05503 done = 1;
05504 break;
05505 default:
05506
05507 cmd = ast_play_and_wait(chan,"vm-forward");
05508 if (!cmd)
05509 cmd = ast_waitfordigit(chan,3000);
05510 if (!cmd)
05511 retries++;
05512 if (retries > 3)
05513 {
05514 cmd = 't';
05515 done = 1;
05516 }
05517
05518 }
05519 }
05520 if (cmd < 0 || cmd == 't')
05521 break;
05522 }
05523
05524 if (use_directory) {
05525
05526
05527 char old_context[sizeof(chan->context)];
05528 char old_exten[sizeof(chan->exten)];
05529 int old_priority;
05530 struct ast_app* app;
05531
05532
05533 app = pbx_findapp("Directory");
05534 if (app) {
05535 char vmcontext[256];
05536
05537 memcpy(old_context, chan->context, sizeof(chan->context));
05538 memcpy(old_exten, chan->exten, sizeof(chan->exten));
05539 old_priority = chan->priority;
05540
05541
05542 snprintf(vmcontext, sizeof(vmcontext), "%s||v", context ? context : "default");
05543 res = pbx_exec(chan, app, vmcontext);
05544
05545 ast_copy_string(username, chan->exten, sizeof(username));
05546
05547
05548 memcpy(chan->context, old_context, sizeof(chan->context));
05549 memcpy(chan->exten, old_exten, sizeof(chan->exten));
05550 chan->priority = old_priority;
05551
05552 } else {
05553 ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
05554 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
05555 }
05556 } else {
05557
05558 res = ast_streamfile(chan, "vm-extension", chan->language);
05559 prompt_played++;
05560 if (res || prompt_played > 4)
05561 break;
05562 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
05563 break;
05564 }
05565
05566
05567 if (ast_strlen_zero(username))
05568 continue;
05569 stringp = username;
05570 s = strsep(&stringp, "*");
05571
05572 valid_extensions = 1;
05573 while (s) {
05574
05575 if ((is_new_message == 1 || strcmp(s,sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
05576 int oldmsgs;
05577 int newmsgs;
05578 int capacity;
05579 if (inboxcount(s, &newmsgs, &oldmsgs)) {
05580 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
05581
05582 res = ast_play_and_wait(chan, "pbx-invalid");
05583 valid_extensions = 0;
05584 break;
05585 }
05586 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
05587 if ((newmsgs + oldmsgs) >= capacity) {
05588 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
05589 res = ast_play_and_wait(chan, "vm-mailboxfull");
05590 valid_extensions = 0;
05591 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
05592 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
05593 free_user(vmtmp);
05594 }
05595 inprocess_count(receiver->mailbox, receiver->context, -1);
05596 break;
05597 }
05598 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
05599 } else {
05600 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
05601
05602 res = ast_play_and_wait(chan, "pbx-invalid");
05603 valid_extensions = 0;
05604 break;
05605 }
05606 s = strsep(&stringp, "*");
05607 }
05608
05609 if (valid_extensions)
05610 break;
05611 }
05612
05613 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
05614 return res;
05615 if (is_new_message == 1) {
05616 struct leave_vm_options leave_options;
05617 char mailbox[AST_MAX_EXTENSION * 2 + 2];
05618
05619 if (context)
05620 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
05621 else
05622 ast_copy_string(mailbox, username, sizeof(mailbox));
05623
05624
05625 memset(&leave_options, 0, sizeof(leave_options));
05626 leave_options.record_gain = record_gain;
05627 cmd = leave_voicemail(chan, mailbox, &leave_options);
05628 } else {
05629
05630 long duration = 0;
05631 struct vm_state vmstmp;
05632 #ifndef IMAP_STORAGE
05633 char msgfile[PATH_MAX];
05634 #endif
05635 int copy_msg_result = 0;
05636
05637 memcpy(&vmstmp, vms, sizeof(vmstmp));
05638
05639 RETRIEVE(dir, curmsg, sender);
05640
05641 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp);
05642 if (!cmd) {
05643 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
05644 #ifdef IMAP_STORAGE
05645 char *myserveremail;
05646 int attach_user_voicemail;
05647
05648 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
05649 if (!dstvms) {
05650 dstvms = create_vm_state_from_user(vmtmp);
05651 }
05652 if (dstvms) {
05653 init_mailstream(dstvms, 0);
05654 if (!dstvms->mailstream) {
05655 ast_log (LOG_ERROR,"IMAP mailstream for %s is NULL\n",vmtmp->mailbox);
05656 } else {
05657 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms);
05658 run_externnotify(vmtmp->context, vmtmp->mailbox);
05659 }
05660 } else {
05661 ast_log (LOG_ERROR,"Could not find state information for mailbox %s\n",vmtmp->mailbox);
05662 }
05663 myserveremail = serveremail;
05664 if (!ast_strlen_zero(vmtmp->serveremail))
05665 myserveremail = vmtmp->serveremail;
05666 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
05667
05668 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);
05669 #else
05670 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir);
05671 #endif
05672 saved_messages++;
05673 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
05674 AST_LIST_REMOVE_CURRENT(&extensions, list);
05675 free_user(vmtmp);
05676 if (res)
05677 break;
05678 }
05679 AST_LIST_TRAVERSE_SAFE_END;
05680 if (saved_messages > 0 && !copy_msg_result) {
05681
05682
05683
05684
05685
05686
05687
05688
05689 res = ast_play_and_wait(chan, "vm-msgsaved");
05690 }
05691 #ifndef IMAP_STORAGE
05692 else {
05693
05694 res = ast_play_and_wait(chan, "vm-mailboxfull");
05695 }
05696
05697 make_file(msgfile, sizeof(msgfile), dir, curmsg);
05698 strcpy(textfile, msgfile);
05699 strcpy(backup, msgfile);
05700 strcpy(backup_textfile, msgfile);
05701 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
05702 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
05703 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
05704 if (ast_fileexists(backup, NULL, NULL) > 0) {
05705 ast_filerename(backup, msgfile, NULL);
05706 rename(backup_textfile, textfile);
05707 }
05708 #endif
05709 }
05710 DISPOSE(dir, curmsg);
05711 #ifndef IMAP_STORAGE
05712 if (cmd) {
05713 make_file(msgfile, sizeof(msgfile), dir, curmsg);
05714 strcpy(textfile, msgfile);
05715 strcpy(backup_textfile, msgfile);
05716 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
05717 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
05718 rename(backup_textfile, textfile);
05719 }
05720 #endif
05721 }
05722
05723
05724 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
05725 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
05726 free_user(vmtmp);
05727 }
05728 return res ? res : cmd;
05729 }
05730
05731 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
05732 {
05733 int res;
05734 if ((res = ast_stream_and_wait(chan, file, chan->language, AST_DIGIT_ANY)) < 0)
05735 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
05736 return res;
05737 }
05738
05739 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
05740 {
05741 return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", "2", skipms);
05742 }
05743
05744 static int play_message_category(struct ast_channel *chan, const char *category)
05745 {
05746 int res = 0;
05747
05748 if (!ast_strlen_zero(category))
05749 res = ast_play_and_wait(chan, category);
05750
05751 if (res) {
05752 ast_log(LOG_WARNING, "No sound file for category '%s' was found.\n", category);
05753 res = 0;
05754 }
05755
05756 return res;
05757 }
05758
05759 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
05760 {
05761 int res = 0;
05762 struct vm_zone *the_zone = NULL;
05763 time_t t;
05764
05765 if (ast_get_time_t(origtime, &t, 0, NULL)) {
05766 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
05767 return 0;
05768 }
05769
05770
05771 if (!ast_strlen_zero(vmu->zonetag)) {
05772
05773 struct vm_zone *z;
05774 AST_LIST_LOCK(&zones);
05775 AST_LIST_TRAVERSE(&zones, z, list) {
05776 if (!strcmp(z->name, vmu->zonetag)) {
05777 the_zone = z;
05778 break;
05779 }
05780 }
05781 AST_LIST_UNLOCK(&zones);
05782 }
05783
05784
05785 #if 0
05786
05787 ast_localtime(&t, &time_now, NULL);
05788 tv_now = ast_tvnow();
05789 tnow = tv_now.tv_sec;
05790 ast_localtime(&tnow, &time_then, NULL);
05791
05792
05793 if (time_now.tm_year == time_then.tm_year)
05794 snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
05795 else
05796 snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
05797 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
05798
05799
05800 #endif
05801 if (the_zone) {
05802 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
05803 } else if (!strncasecmp(chan->language, "de", 2)) {
05804 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05805 } else if (!strncasecmp(chan->language, "gr", 2)) {
05806 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
05807 } else if (!strncasecmp(chan->language, "he", 2)) {
05808 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'at2' kM", NULL);
05809 } else if (!strncasecmp(chan->language, "it", 2)) {
05810 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);
05811 } else if (!strncasecmp(chan->language, "nl", 2)) {
05812 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
05813 } else if (!strncasecmp(chan->language, "no", 2)) {
05814 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05815 } else if (!strncasecmp(chan->language, "pl", 2)) {
05816 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
05817 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
05818 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);
05819 } else if (!strncasecmp(chan->language, "se", 2)) {
05820 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
05821 } else {
05822 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
05823 }
05824 #if 0
05825 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
05826 #endif
05827 return res;
05828 }
05829
05830
05831
05832 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
05833 {
05834 int res = 0;
05835 int i;
05836 char *callerid, *name;
05837 char prefile[PATH_MAX] = "";
05838
05839
05840
05841
05842 if ((cid == NULL)||(context == NULL))
05843 return res;
05844
05845
05846 if (option_debug > 2)
05847 ast_log(LOG_DEBUG, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
05848 ast_callerid_parse(cid, &name, &callerid);
05849 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
05850
05851
05852 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
05853 if (option_debug > 2)
05854 ast_log(LOG_DEBUG, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
05855 if ((strcmp(cidinternalcontexts[i], context) == 0))
05856 break;
05857 }
05858 if (i != MAX_NUM_CID_CONTEXTS){
05859 if (!res) {
05860 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
05861 if (!ast_strlen_zero(prefile)) {
05862
05863 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05864 if (option_verbose > 2)
05865 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
05866 if (!callback)
05867 res = wait_file2(chan, vms, "vm-from");
05868 res = ast_stream_and_wait(chan, prefile, chan->language, "");
05869 } else {
05870 if (option_verbose > 2)
05871 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: message from '%s'\n", callerid);
05872
05873 if (!callback)
05874 res = wait_file2(chan, vms, "vm-from-extension");
05875 res = ast_say_digit_str(chan, callerid, "", chan->language);
05876 }
05877 }
05878 }
05879 }
05880
05881 else if (!res){
05882 if (option_debug > 2)
05883 ast_log(LOG_DEBUG, "VM-CID: Numeric caller id: (%s)\n",callerid);
05884
05885 if (!callback)
05886 res = wait_file2(chan, vms, "vm-from-phonenumber");
05887 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
05888 }
05889 } else {
05890
05891 if (option_debug)
05892 ast_log(LOG_DEBUG, "VM-CID: From an unknown number\n");
05893
05894 res = wait_file2(chan, vms, "vm-unknown-caller");
05895 }
05896 return res;
05897 }
05898
05899 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
05900 {
05901 int res = 0;
05902 int durationm;
05903 int durations;
05904
05905 if (duration == NULL)
05906 return res;
05907
05908
05909 durations=atoi(duration);
05910 durationm=(durations / 60);
05911
05912 if (option_debug > 2)
05913 ast_log(LOG_DEBUG, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
05914
05915 if ((!res) && (durationm >= minduration)) {
05916 res = wait_file2(chan, vms, "vm-duration");
05917
05918
05919 if (!strncasecmp(chan->language, "pl", 2)) {
05920 div_t num = div(durationm, 10);
05921
05922 if (durationm == 1) {
05923 res = ast_play_and_wait(chan, "digits/1z");
05924 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
05925 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
05926 if (num.rem == 2) {
05927 if (!num.quot) {
05928 res = ast_play_and_wait(chan, "digits/2-ie");
05929 } else {
05930 res = say_and_wait(chan, durationm - 2 , chan->language);
05931 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
05932 }
05933 } else {
05934 res = say_and_wait(chan, durationm, chan->language);
05935 }
05936 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
05937 } else {
05938 res = say_and_wait(chan, durationm, chan->language);
05939 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
05940 }
05941
05942 } else {
05943 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
05944 res = wait_file2(chan, vms, "vm-minutes");
05945 }
05946 }
05947 return res;
05948 }
05949
05950 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
05951 {
05952 int res = 0;
05953 char filename[256], *cid;
05954 const char *origtime, *context, *category, *duration;
05955 struct ast_config *msg_cfg;
05956
05957 vms->starting = 0;
05958 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
05959 adsi_message(chan, vms);
05960
05961 if (!strncasecmp(chan->language, "he", 2)) {
05962
05963
05964
05965
05966 if (!vms->curmsg) {
05967 res = wait_file2(chan, vms, "vm-message");
05968 res = wait_file2(chan, vms, "vm-first");
05969 } else if (vms->curmsg == vms->lastmsg) {
05970 res = wait_file2(chan, vms, "vm-message");
05971 res = wait_file2(chan, vms, "vm-last");
05972 } else {
05973 res = wait_file2(chan, vms, "vm-message");
05974 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05975 ast_log(LOG_DEBUG, "curmsg: %d\n", vms->curmsg);
05976 ast_log(LOG_DEBUG, "lagmsg: %d\n", vms->lastmsg);
05977 if (!res) {
05978 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
05979 }
05980 }
05981 }
05982
05983 } else if (!strncasecmp(chan->language, "pl", 2)) {
05984 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05985 int ten, one;
05986 char nextmsg[256];
05987 ten = (vms->curmsg + 1) / 10;
05988 one = (vms->curmsg + 1) % 10;
05989
05990 if (vms->curmsg < 20) {
05991 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
05992 res = wait_file2(chan, vms, nextmsg);
05993 } else {
05994 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
05995 res = wait_file2(chan, vms, nextmsg);
05996 if (one > 0) {
05997 if (!res) {
05998 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
05999 res = wait_file2(chan, vms, nextmsg);
06000 }
06001 }
06002 }
06003 }
06004 if (!res)
06005 res = wait_file2(chan, vms, "vm-message");
06006
06007 } else if (!strncasecmp(chan->language, "se", 2)) {
06008 if (!vms->curmsg)
06009 res = wait_file2(chan, vms, "vm-first");
06010 else if (vms->curmsg == vms->lastmsg)
06011 res = wait_file2(chan, vms, "vm-last");
06012 res = wait_file2(chan, vms, "vm-meddelandet");
06013 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
06014 if (!res)
06015 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
06016 }
06017
06018
06019
06020
06021
06022 } else {
06023 if (!vms->curmsg)
06024 res = wait_file2(chan, vms, "vm-first");
06025 else if (vms->curmsg == vms->lastmsg)
06026 res = wait_file2(chan, vms, "vm-last");
06027 res = wait_file2(chan, vms, "vm-message");
06028 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
06029 if (!res)
06030 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
06031 }
06032 }
06033
06034
06035 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
06036 snprintf(filename, sizeof(filename), "%s.txt", vms->fn2);
06037 RETRIEVE(vms->curdir, vms->curmsg, vmu);
06038 msg_cfg = ast_config_load(filename);
06039 if (!msg_cfg) {
06040 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
06041 return 0;
06042 }
06043
06044 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
06045 ast_log(LOG_WARNING, "No origtime?!\n");
06046 DISPOSE(vms->curdir, vms->curmsg);
06047 ast_config_destroy(msg_cfg);
06048 return 0;
06049 }
06050
06051 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
06052 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
06053 category = ast_variable_retrieve(msg_cfg, "message", "category");
06054
06055 context = ast_variable_retrieve(msg_cfg, "message", "context");
06056 if (!strncasecmp("macro",context,5))
06057 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
06058 if (!res)
06059 res = play_message_category(chan, category);
06060 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
06061 res = play_message_datetime(chan, vmu, origtime, filename);
06062 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
06063 res = play_message_callerid(chan, vms, cid, context, 0);
06064 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
06065 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
06066
06067 if (res == '1')
06068 res = 0;
06069 ast_config_destroy(msg_cfg);
06070
06071 if (!res) {
06072 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
06073 vms->heard[vms->curmsg] = 1;
06074 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
06075 ast_log(LOG_WARNING, "Playback of message %s failed\n", vms->fn);
06076 res = 0;
06077 }
06078 }
06079 DISPOSE(vms->curdir, vms->curmsg);
06080 return res;
06081 }
06082
06083 #ifndef IMAP_STORAGE
06084 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
06085 {
06086 int count_msg, last_msg;
06087
06088 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
06089
06090
06091
06092
06093 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
06094
06095
06096 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
06097
06098
06099 count_msg = count_messages(vmu, vms->curdir);
06100 if (count_msg < 0)
06101 return count_msg;
06102 else
06103 vms->lastmsg = count_msg - 1;
06104
06105 if (vm_allocate_dh(vms, vmu, count_msg)) {
06106 return -1;
06107 }
06108
06109
06110
06111
06112
06113
06114
06115
06116
06117 last_msg = last_message_index(vmu, vms->curdir);
06118
06119 if (last_msg < -1) {
06120 return last_msg;
06121 } else if (vms->lastmsg != last_msg) {
06122 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);
06123 resequence_mailbox(vmu, vms->curdir, count_msg);
06124 }
06125
06126 return 0;
06127 }
06128 #endif
06129
06130 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
06131 {
06132 int x = 0;
06133 #ifndef IMAP_STORAGE
06134 int last_msg_index;
06135 int res = 0, nummsg;
06136 #endif
06137
06138 if (vms->lastmsg <= -1)
06139 goto done;
06140
06141 vms->curmsg = -1;
06142 #ifndef IMAP_STORAGE
06143
06144 if (vm_lock_path(vms->curdir))
06145 return ERROR_LOCK_PATH;
06146
06147 last_msg_index = last_message_index(vmu, vms->curdir);
06148 if (last_msg_index != vms->lastmsg) {
06149 ast_log(LOG_NOTICE, "%d messages arrived while mailbox was open\n", last_msg_index - vms->lastmsg);
06150 }
06151
06152
06153 for (x = 0; x < last_msg_index + 1; x++) {
06154 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
06155
06156 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
06157 if (!EXISTS(vms->curdir, x, vms->fn, NULL))
06158 break;
06159 vms->curmsg++;
06160 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
06161 if (strcmp(vms->fn, vms->fn2)) {
06162 RENAME(vms->curdir, x, vmu->mailbox,vmu->context, vms->curdir, vms->curmsg, vms->fn, vms->fn2);
06163 }
06164 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
06165
06166 res = save_to_folder(vmu, vms, x, 1);
06167 if (res == ERROR_LOCK_PATH || res == ERROR_MAILBOX_FULL) {
06168
06169 ast_log(LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
06170 vms->deleted[x] = 0;
06171 vms->heard[x] = 0;
06172 --x;
06173 }
06174 }
06175 }
06176
06177
06178 nummsg = x - 1;
06179 for (x = vms->curmsg + 1; x <= nummsg; x++) {
06180 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
06181 if (EXISTS(vms->curdir, x, vms->fn, NULL))
06182 DELETE(vms->curdir, x, vms->fn, vmu);
06183 }
06184 ast_unlock_path(vms->curdir);
06185 #else
06186 if (vms->deleted) {
06187
06188
06189 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
06190 if (vms->deleted[x]) {
06191 if (option_debug > 2) {
06192 ast_log(LOG_DEBUG, "IMAP delete of %d\n", x);
06193 }
06194 DELETE(vms->curdir, x, vms->fn, vmu);
06195 }
06196 }
06197 }
06198 #endif
06199
06200 done:
06201 if (vms->deleted)
06202 memset(vms->deleted, 0, vms->dh_arraysize * sizeof(int));
06203 if (vms->heard)
06204 memset(vms->heard, 0, vms->dh_arraysize * sizeof(int));
06205
06206 return 0;
06207 }
06208
06209
06210
06211
06212
06213
06214
06215 static int vm_play_folder_name_gr(struct ast_channel *chan, char *mbox)
06216 {
06217 int cmd;
06218 char *buf;
06219
06220 buf = alloca(strlen(mbox)+2);
06221 strcpy(buf, mbox);
06222 strcat(buf,"s");
06223
06224 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")){
06225 cmd = ast_play_and_wait(chan, buf);
06226 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06227 } else {
06228 cmd = ast_play_and_wait(chan, "vm-messages");
06229 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06230 }
06231 }
06232
06233 static int vm_play_folder_name_pl(struct ast_channel *chan, char *mbox)
06234 {
06235 int cmd;
06236
06237 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")) {
06238 if (!strcasecmp(mbox, "vm-INBOX"))
06239 cmd = ast_play_and_wait(chan, "vm-new-e");
06240 else
06241 cmd = ast_play_and_wait(chan, "vm-old-e");
06242 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06243 } else {
06244 cmd = ast_play_and_wait(chan, "vm-messages");
06245 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06246 }
06247 }
06248
06249 static int vm_play_folder_name_ua(struct ast_channel *chan, char *mbox)
06250 {
06251 int cmd;
06252
06253 if (!strcasecmp(mbox, "vm-Family") || !strcasecmp(mbox, "vm-Friends") || !strcasecmp(mbox, "vm-Work")){
06254 cmd = ast_play_and_wait(chan, "vm-messages");
06255 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06256 } else {
06257 cmd = ast_play_and_wait(chan, mbox);
06258 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06259 }
06260 }
06261
06262 static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
06263 {
06264 int cmd;
06265
06266 if ( !strncasecmp(chan->language, "it", 2) ||
06267 !strncasecmp(chan->language, "es", 2) ||
06268 !strncasecmp(chan->language, "pt", 2)) {
06269 cmd = ast_play_and_wait(chan, "vm-messages");
06270 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06271 } else if (!strncasecmp(chan->language, "gr", 2)) {
06272 return vm_play_folder_name_gr(chan, mbox);
06273 } else if (!strncasecmp(chan->language, "pl", 2)) {
06274 return vm_play_folder_name_pl(chan, mbox);
06275 } else if (!strncasecmp(chan->language, "ua", 2)) {
06276 return vm_play_folder_name_ua(chan, mbox);
06277 } else if (!strncasecmp(chan->language, "he", 2)) {
06278 cmd = ast_play_and_wait(chan, mbox);
06279 return cmd;
06280 } else {
06281 cmd = ast_play_and_wait(chan, mbox);
06282 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06283 }
06284 }
06285
06286
06287
06288
06289
06290
06291
06292
06293
06294
06295
06296
06297
06298 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
06299 {
06300 int res = 0;
06301
06302 if (vms->newmessages) {
06303 res = ast_play_and_wait(chan, "vm-youhave");
06304 if (!res)
06305 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
06306 if (!res) {
06307 if ((vms->newmessages == 1)) {
06308 res = ast_play_and_wait(chan, "vm-INBOX");
06309 if (!res)
06310 res = ast_play_and_wait(chan, "vm-message");
06311 } else {
06312 res = ast_play_and_wait(chan, "vm-INBOXs");
06313 if (!res)
06314 res = ast_play_and_wait(chan, "vm-messages");
06315 }
06316 }
06317 } else if (vms->oldmessages){
06318 res = ast_play_and_wait(chan, "vm-youhave");
06319 if (!res)
06320 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
06321 if ((vms->oldmessages == 1)){
06322 res = ast_play_and_wait(chan, "vm-Old");
06323 if (!res)
06324 res = ast_play_and_wait(chan, "vm-message");
06325 } else {
06326 res = ast_play_and_wait(chan, "vm-Olds");
06327 if (!res)
06328 res = ast_play_and_wait(chan, "vm-messages");
06329 }
06330 } else if (!vms->oldmessages && !vms->newmessages)
06331 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
06332 return res;
06333 }
06334
06335
06336 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
06337 {
06338 int res;
06339
06340
06341 res = ast_play_and_wait(chan, "vm-youhave");
06342 if (!res) {
06343 if (vms->newmessages) {
06344 res = say_and_wait(chan, vms->newmessages, chan->language);
06345 if (!res)
06346 res = ast_play_and_wait(chan, "vm-INBOX");
06347 if (vms->oldmessages && !res)
06348 res = ast_play_and_wait(chan, "vm-and");
06349 else if (!res) {
06350 if ((vms->newmessages == 1))
06351 res = ast_play_and_wait(chan, "vm-message");
06352 else
06353 res = ast_play_and_wait(chan, "vm-messages");
06354 }
06355
06356 }
06357 if (!res && vms->oldmessages) {
06358 res = say_and_wait(chan, vms->oldmessages, chan->language);
06359 if (!res)
06360 res = ast_play_and_wait(chan, "vm-Old");
06361 if (!res) {
06362 if (vms->oldmessages == 1)
06363 res = ast_play_and_wait(chan, "vm-message");
06364 else
06365 res = ast_play_and_wait(chan, "vm-messages");
06366 }
06367 }
06368 if (!res) {
06369 if (!vms->oldmessages && !vms->newmessages) {
06370 res = ast_play_and_wait(chan, "vm-no");
06371 if (!res)
06372 res = ast_play_and_wait(chan, "vm-messages");
06373 }
06374 }
06375 }
06376 return res;
06377 }
06378
06379
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 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
06437 {
06438 int res;
06439 int lastnum = 0;
06440
06441 res = ast_play_and_wait(chan, "vm-youhave");
06442
06443 if (!res && vms->newmessages) {
06444 lastnum = vms->newmessages;
06445
06446 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
06447 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
06448 }
06449
06450 if (!res && vms->oldmessages) {
06451 res = ast_play_and_wait(chan, "vm-and");
06452 }
06453 }
06454
06455 if (!res && vms->oldmessages) {
06456 lastnum = vms->oldmessages;
06457
06458 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
06459 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
06460 }
06461 }
06462
06463 if (!res) {
06464 if (lastnum == 0) {
06465 res = ast_play_and_wait(chan, "vm-no");
06466 }
06467 if (!res) {
06468 res = ast_say_counted_noun(chan, lastnum, "vm-message");
06469 }
06470 }
06471
06472 return res;
06473 }
06474
06475
06476 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
06477 {
06478 int res=0;
06479
06480
06481 if (!res) {
06482 if ((vms->newmessages) || (vms->oldmessages)) {
06483 res = ast_play_and_wait(chan, "vm-youhave");
06484 }
06485
06486
06487
06488
06489
06490 if (vms->newmessages) {
06491 if (!res) {
06492 if (vms->newmessages == 1) {
06493 res = ast_play_and_wait(chan, "vm-INBOX1");
06494 } else {
06495 if (vms->newmessages == 2) {
06496 res = ast_play_and_wait(chan, "vm-shtei");
06497 } else {
06498 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06499 }
06500 res = ast_play_and_wait(chan, "vm-INBOX");
06501 }
06502 }
06503 if (vms->oldmessages && !res) {
06504 res = ast_play_and_wait(chan, "vm-and");
06505 if (vms->oldmessages == 1) {
06506 res = ast_play_and_wait(chan, "vm-Old1");
06507 } else {
06508 if (vms->oldmessages == 2) {
06509 res = ast_play_and_wait(chan, "vm-shtei");
06510 } else {
06511 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06512 }
06513 res = ast_play_and_wait(chan, "vm-Old");
06514 }
06515 }
06516 }
06517 if (!res && vms->oldmessages && !vms->newmessages) {
06518 if (!res) {
06519 if (vms->oldmessages == 1) {
06520 res = ast_play_and_wait(chan, "vm-Old1");
06521 } else {
06522 if (vms->oldmessages == 2) {
06523 res = ast_play_and_wait(chan, "vm-shtei");
06524 } else {
06525 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06526 }
06527 res = ast_play_and_wait(chan, "vm-Old");
06528 }
06529 }
06530 }
06531 if (!res) {
06532 if (!vms->oldmessages && !vms->newmessages) {
06533 if (!res) {
06534 res = ast_play_and_wait(chan, "vm-nomessages");
06535 }
06536 }
06537 }
06538 }
06539 return res;
06540 }
06541
06542
06543
06544 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
06545 {
06546
06547 int res;
06548 if (!vms->oldmessages && !vms->newmessages)
06549 res = ast_play_and_wait(chan, "vm-no") ||
06550 ast_play_and_wait(chan, "vm-message");
06551 else
06552 res = ast_play_and_wait(chan, "vm-youhave");
06553 if (!res && vms->newmessages) {
06554 res = (vms->newmessages == 1) ?
06555 ast_play_and_wait(chan, "digits/un") ||
06556 ast_play_and_wait(chan, "vm-nuovo") ||
06557 ast_play_and_wait(chan, "vm-message") :
06558
06559 say_and_wait(chan, vms->newmessages, chan->language) ||
06560 ast_play_and_wait(chan, "vm-nuovi") ||
06561 ast_play_and_wait(chan, "vm-messages");
06562 if (!res && vms->oldmessages)
06563 res = ast_play_and_wait(chan, "vm-and");
06564 }
06565 if (!res && vms->oldmessages) {
06566 res = (vms->oldmessages == 1) ?
06567 ast_play_and_wait(chan, "digits/un") ||
06568 ast_play_and_wait(chan, "vm-vecchio") ||
06569 ast_play_and_wait(chan, "vm-message") :
06570
06571 say_and_wait(chan, vms->oldmessages, chan->language) ||
06572 ast_play_and_wait(chan, "vm-vecchi") ||
06573 ast_play_and_wait(chan, "vm-messages");
06574 }
06575 return res;
06576 }
06577
06578
06579 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
06580 {
06581
06582 int res;
06583 div_t num;
06584
06585 if (!vms->oldmessages && !vms->newmessages) {
06586 res = ast_play_and_wait(chan, "vm-no");
06587 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06588 return res;
06589 } else {
06590 res = ast_play_and_wait(chan, "vm-youhave");
06591 }
06592
06593 if (vms->newmessages) {
06594 num = div(vms->newmessages, 10);
06595 if (vms->newmessages == 1) {
06596 res = ast_play_and_wait(chan, "digits/1-a");
06597 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
06598 res = res ? res : ast_play_and_wait(chan, "vm-message");
06599 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06600 if (num.rem == 2) {
06601 if (!num.quot) {
06602 res = ast_play_and_wait(chan, "digits/2-ie");
06603 } else {
06604 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
06605 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06606 }
06607 } else {
06608 res = say_and_wait(chan, vms->newmessages, chan->language);
06609 }
06610 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
06611 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06612 } else {
06613 res = say_and_wait(chan, vms->newmessages, chan->language);
06614 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
06615 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06616 }
06617 if (!res && vms->oldmessages)
06618 res = ast_play_and_wait(chan, "vm-and");
06619 }
06620 if (!res && vms->oldmessages) {
06621 num = div(vms->oldmessages, 10);
06622 if (vms->oldmessages == 1) {
06623 res = ast_play_and_wait(chan, "digits/1-a");
06624 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
06625 res = res ? res : ast_play_and_wait(chan, "vm-message");
06626 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06627 if (num.rem == 2) {
06628 if (!num.quot) {
06629 res = ast_play_and_wait(chan, "digits/2-ie");
06630 } else {
06631 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
06632 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06633 }
06634 } else {
06635 res = say_and_wait(chan, vms->oldmessages, chan->language);
06636 }
06637 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
06638 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06639 } else {
06640 res = say_and_wait(chan, vms->oldmessages, chan->language);
06641 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
06642 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06643 }
06644 }
06645
06646 return res;
06647 }
06648
06649
06650 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
06651 {
06652
06653 int res;
06654
06655 res = ast_play_and_wait(chan, "vm-youhave");
06656 if (res)
06657 return res;
06658
06659 if (!vms->oldmessages && !vms->newmessages) {
06660 res = ast_play_and_wait(chan, "vm-no");
06661 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06662 return res;
06663 }
06664
06665 if (vms->newmessages) {
06666 if ((vms->newmessages == 1)) {
06667 res = ast_play_and_wait(chan, "digits/ett");
06668 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
06669 res = res ? res : ast_play_and_wait(chan, "vm-message");
06670 } else {
06671 res = say_and_wait(chan, vms->newmessages, chan->language);
06672 res = res ? res : ast_play_and_wait(chan, "vm-nya");
06673 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06674 }
06675 if (!res && vms->oldmessages)
06676 res = ast_play_and_wait(chan, "vm-and");
06677 }
06678 if (!res && vms->oldmessages) {
06679 if (vms->oldmessages == 1) {
06680 res = ast_play_and_wait(chan, "digits/ett");
06681 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
06682 res = res ? res : ast_play_and_wait(chan, "vm-message");
06683 } else {
06684 res = say_and_wait(chan, vms->oldmessages, chan->language);
06685 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
06686 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06687 }
06688 }
06689
06690 return res;
06691 }
06692
06693
06694 static int vm_intro_no(struct ast_channel *chan,struct vm_state *vms)
06695 {
06696
06697 int res;
06698
06699 res = ast_play_and_wait(chan, "vm-youhave");
06700 if (res)
06701 return res;
06702
06703 if (!vms->oldmessages && !vms->newmessages) {
06704 res = ast_play_and_wait(chan, "vm-no");
06705 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06706 return res;
06707 }
06708
06709 if (vms->newmessages) {
06710 if ((vms->newmessages == 1)) {
06711 res = ast_play_and_wait(chan, "digits/1");
06712 res = res ? res : ast_play_and_wait(chan, "vm-ny");
06713 res = res ? res : ast_play_and_wait(chan, "vm-message");
06714 } else {
06715 res = say_and_wait(chan, vms->newmessages, chan->language);
06716 res = res ? res : ast_play_and_wait(chan, "vm-nye");
06717 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06718 }
06719 if (!res && vms->oldmessages)
06720 res = ast_play_and_wait(chan, "vm-and");
06721 }
06722 if (!res && vms->oldmessages) {
06723 if (vms->oldmessages == 1) {
06724 res = ast_play_and_wait(chan, "digits/1");
06725 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
06726 res = res ? res : ast_play_and_wait(chan, "vm-message");
06727 } else {
06728 res = say_and_wait(chan, vms->oldmessages, chan->language);
06729 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
06730 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06731 }
06732 }
06733
06734 return res;
06735 }
06736
06737
06738 static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
06739 {
06740
06741 int res;
06742 res = ast_play_and_wait(chan, "vm-youhave");
06743 if (!res) {
06744 if (vms->newmessages) {
06745 if ((vms->newmessages == 1))
06746 res = ast_play_and_wait(chan, "digits/1F");
06747 else
06748 res = say_and_wait(chan, vms->newmessages, chan->language);
06749 if (!res)
06750 res = ast_play_and_wait(chan, "vm-INBOX");
06751 if (vms->oldmessages && !res)
06752 res = ast_play_and_wait(chan, "vm-and");
06753 else if (!res) {
06754 if ((vms->newmessages == 1))
06755 res = ast_play_and_wait(chan, "vm-message");
06756 else
06757 res = ast_play_and_wait(chan, "vm-messages");
06758 }
06759
06760 }
06761 if (!res && vms->oldmessages) {
06762 if (vms->oldmessages == 1)
06763 res = ast_play_and_wait(chan, "digits/1F");
06764 else
06765 res = say_and_wait(chan, vms->oldmessages, chan->language);
06766 if (!res)
06767 res = ast_play_and_wait(chan, "vm-Old");
06768 if (!res) {
06769 if (vms->oldmessages == 1)
06770 res = ast_play_and_wait(chan, "vm-message");
06771 else
06772 res = ast_play_and_wait(chan, "vm-messages");
06773 }
06774 }
06775 if (!res) {
06776 if (!vms->oldmessages && !vms->newmessages) {
06777 res = ast_play_and_wait(chan, "vm-no");
06778 if (!res)
06779 res = ast_play_and_wait(chan, "vm-messages");
06780 }
06781 }
06782 }
06783 return res;
06784 }
06785
06786
06787 static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
06788 {
06789
06790 int res;
06791 if (!vms->oldmessages && !vms->newmessages) {
06792 res = ast_play_and_wait(chan, "vm-youhaveno");
06793 if (!res)
06794 res = ast_play_and_wait(chan, "vm-messages");
06795 } else {
06796 res = ast_play_and_wait(chan, "vm-youhave");
06797 }
06798 if (!res) {
06799 if (vms->newmessages) {
06800 if (!res) {
06801 if ((vms->newmessages == 1)) {
06802 res = ast_play_and_wait(chan, "digits/1");
06803 if (!res)
06804 res = ast_play_and_wait(chan, "vm-message");
06805 if (!res)
06806 res = ast_play_and_wait(chan, "vm-INBOXs");
06807 } else {
06808 res = say_and_wait(chan, vms->newmessages, chan->language);
06809 if (!res)
06810 res = ast_play_and_wait(chan, "vm-messages");
06811 if (!res)
06812 res = ast_play_and_wait(chan, "vm-INBOX");
06813 }
06814 }
06815 if (vms->oldmessages && !res)
06816 res = ast_play_and_wait(chan, "vm-and");
06817 }
06818 if (vms->oldmessages) {
06819 if (!res) {
06820 if (vms->oldmessages == 1) {
06821 res = ast_play_and_wait(chan, "digits/1");
06822 if (!res)
06823 res = ast_play_and_wait(chan, "vm-message");
06824 if (!res)
06825 res = ast_play_and_wait(chan, "vm-Olds");
06826 } else {
06827 res = say_and_wait(chan, vms->oldmessages, chan->language);
06828 if (!res)
06829 res = ast_play_and_wait(chan, "vm-messages");
06830 if (!res)
06831 res = ast_play_and_wait(chan, "vm-Old");
06832 }
06833 }
06834 }
06835 }
06836 return res;
06837 }
06838
06839
06840 static int vm_intro_pt_BR(struct ast_channel *chan,struct vm_state *vms) {
06841
06842 int res;
06843 if (!vms->oldmessages && !vms->newmessages) {
06844 res = ast_play_and_wait(chan, "vm-nomessages");
06845 return res;
06846 }
06847 else {
06848 res = ast_play_and_wait(chan, "vm-youhave");
06849 }
06850 if (vms->newmessages) {
06851 if (!res)
06852 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06853 if ((vms->newmessages == 1)) {
06854 if (!res)
06855 res = ast_play_and_wait(chan, "vm-message");
06856 if (!res)
06857 res = ast_play_and_wait(chan, "vm-INBOXs");
06858 }
06859 else {
06860 if (!res)
06861 res = ast_play_and_wait(chan, "vm-messages");
06862 if (!res)
06863 res = ast_play_and_wait(chan, "vm-INBOX");
06864 }
06865 if (vms->oldmessages && !res)
06866 res = ast_play_and_wait(chan, "vm-and");
06867 }
06868 if (vms->oldmessages) {
06869 if (!res)
06870 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06871 if (vms->oldmessages == 1) {
06872 if (!res)
06873 res = ast_play_and_wait(chan, "vm-message");
06874 if (!res)
06875 res = ast_play_and_wait(chan, "vm-Olds");
06876 }
06877 else {
06878 if (!res)
06879 res = ast_play_and_wait(chan, "vm-messages");
06880 if (!res)
06881 res = ast_play_and_wait(chan, "vm-Old");
06882 }
06883 }
06884 return res;
06885 }
06886
06887
06888 static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
06889 {
06890
06891 int res;
06892 res = ast_play_and_wait(chan, "vm-youhave");
06893 if (!res) {
06894 if (vms->newmessages) {
06895 res = say_and_wait(chan, vms->newmessages, chan->language);
06896 if (!res)
06897 res = ast_play_and_wait(chan, "vm-INBOX");
06898 if (vms->oldmessages && !res)
06899 res = ast_play_and_wait(chan, "vm-and");
06900 else if (!res) {
06901 if ((vms->newmessages == 1))
06902 res = ast_play_and_wait(chan, "vm-message");
06903 else
06904 res = ast_play_and_wait(chan, "vm-messages");
06905 }
06906
06907 }
06908 if (!res && vms->oldmessages) {
06909 res = say_and_wait(chan, vms->oldmessages, chan->language);
06910 if (!res)
06911 res = ast_play_and_wait(chan, "vm-Old");
06912 if (!res) {
06913 if (vms->oldmessages == 1)
06914 res = ast_play_and_wait(chan, "vm-message");
06915 else
06916 res = ast_play_and_wait(chan, "vm-messages");
06917 }
06918 }
06919 if (!res) {
06920 if (!vms->oldmessages && !vms->newmessages) {
06921 res = ast_play_and_wait(chan, "vm-no");
06922 if (!res)
06923 res = ast_play_and_wait(chan, "vm-messages");
06924 }
06925 }
06926 }
06927 return res;
06928 }
06929
06930
06931 static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
06932 {
06933
06934 int res;
06935 res = ast_play_and_wait(chan, "vm-youhave");
06936 if (!res) {
06937 if (vms->newmessages) {
06938 res = say_and_wait(chan, vms->newmessages, chan->language);
06939 if (!res) {
06940 if (vms->newmessages == 1)
06941 res = ast_play_and_wait(chan, "vm-INBOXs");
06942 else
06943 res = ast_play_and_wait(chan, "vm-INBOX");
06944 }
06945 if (vms->oldmessages && !res)
06946 res = ast_play_and_wait(chan, "vm-and");
06947 else if (!res) {
06948 if ((vms->newmessages == 1))
06949 res = ast_play_and_wait(chan, "vm-message");
06950 else
06951 res = ast_play_and_wait(chan, "vm-messages");
06952 }
06953
06954 }
06955 if (!res && vms->oldmessages) {
06956 res = say_and_wait(chan, vms->oldmessages, chan->language);
06957 if (!res) {
06958 if (vms->oldmessages == 1)
06959 res = ast_play_and_wait(chan, "vm-Olds");
06960 else
06961 res = ast_play_and_wait(chan, "vm-Old");
06962 }
06963 if (!res) {
06964 if (vms->oldmessages == 1)
06965 res = ast_play_and_wait(chan, "vm-message");
06966 else
06967 res = ast_play_and_wait(chan, "vm-messages");
06968 }
06969 }
06970 if (!res) {
06971 if (!vms->oldmessages && !vms->newmessages) {
06972 res = ast_play_and_wait(chan, "vm-no");
06973 if (!res)
06974 res = ast_play_and_wait(chan, "vm-messages");
06975 }
06976 }
06977 }
06978 return res;
06979 }
06980
06981
06982 static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
06983 {
06984
06985 int res;
06986 res = ast_play_and_wait(chan, "vm-youhave");
06987 if (!res) {
06988 if (vms->newmessages) {
06989 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06990 if (!res) {
06991 if ((vms->newmessages == 1)) {
06992 res = ast_play_and_wait(chan, "vm-message");
06993 if (!res)
06994 res = ast_play_and_wait(chan, "vm-INBOXs");
06995 } else {
06996 res = ast_play_and_wait(chan, "vm-messages");
06997 if (!res)
06998 res = ast_play_and_wait(chan, "vm-INBOX");
06999 }
07000 }
07001 if (vms->oldmessages && !res)
07002 res = ast_play_and_wait(chan, "vm-and");
07003 }
07004 if (!res && vms->oldmessages) {
07005 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07006 if (!res) {
07007 if (vms->oldmessages == 1) {
07008 res = ast_play_and_wait(chan, "vm-message");
07009 if (!res)
07010 res = ast_play_and_wait(chan, "vm-Olds");
07011 } else {
07012 res = ast_play_and_wait(chan, "vm-messages");
07013 if (!res)
07014 res = ast_play_and_wait(chan, "vm-Old");
07015 }
07016 }
07017 }
07018 if (!res) {
07019 if (!vms->oldmessages && !vms->newmessages) {
07020 res = ast_play_and_wait(chan, "vm-no");
07021 if (!res)
07022 res = ast_play_and_wait(chan, "vm-messages");
07023 }
07024 }
07025 }
07026 return res;
07027 }
07028
07029
07030
07031
07032
07033
07034
07035
07036
07037
07038
07039
07040
07041
07042
07043
07044
07045 static int vm_intro_cs(struct ast_channel *chan,struct vm_state *vms)
07046 {
07047 int res;
07048 res = ast_play_and_wait(chan, "vm-youhave");
07049 if (!res) {
07050 if (vms->newmessages) {
07051 if (vms->newmessages == 1) {
07052 res = ast_play_and_wait(chan, "digits/jednu");
07053 } else {
07054 res = say_and_wait(chan, vms->newmessages, chan->language);
07055 }
07056 if (!res) {
07057 if ((vms->newmessages == 1))
07058 res = ast_play_and_wait(chan, "vm-novou");
07059 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
07060 res = ast_play_and_wait(chan, "vm-nove");
07061 if (vms->newmessages > 4)
07062 res = ast_play_and_wait(chan, "vm-novych");
07063 }
07064 if (vms->oldmessages && !res)
07065 res = ast_play_and_wait(chan, "vm-and");
07066 else if (!res) {
07067 if ((vms->newmessages == 1))
07068 res = ast_play_and_wait(chan, "vm-zpravu");
07069 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
07070 res = ast_play_and_wait(chan, "vm-zpravy");
07071 if (vms->newmessages > 4)
07072 res = ast_play_and_wait(chan, "vm-zprav");
07073 }
07074 }
07075 if (!res && vms->oldmessages) {
07076 res = say_and_wait(chan, vms->oldmessages, chan->language);
07077 if (!res) {
07078 if ((vms->oldmessages == 1))
07079 res = ast_play_and_wait(chan, "vm-starou");
07080 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
07081 res = ast_play_and_wait(chan, "vm-stare");
07082 if (vms->oldmessages > 4)
07083 res = ast_play_and_wait(chan, "vm-starych");
07084 }
07085 if (!res) {
07086 if ((vms->oldmessages == 1))
07087 res = ast_play_and_wait(chan, "vm-zpravu");
07088 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
07089 res = ast_play_and_wait(chan, "vm-zpravy");
07090 if (vms->oldmessages > 4)
07091 res = ast_play_and_wait(chan, "vm-zprav");
07092 }
07093 }
07094 if (!res) {
07095 if (!vms->oldmessages && !vms->newmessages) {
07096 res = ast_play_and_wait(chan, "vm-no");
07097 if (!res)
07098 res = ast_play_and_wait(chan, "vm-zpravy");
07099 }
07100 }
07101 }
07102 return res;
07103 }
07104
07105 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07106 {
07107 char prefile[256];
07108
07109
07110 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07111 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
07112 RETRIEVE(prefile, -1, vmu);
07113 if (ast_fileexists(prefile, NULL, NULL) > 0)
07114 ast_play_and_wait(chan, "vm-tempgreetactive");
07115 DISPOSE(prefile, -1);
07116 }
07117
07118
07119 if (0) {
07120 return 0;
07121 } else if (!strncasecmp(chan->language, "cs", 2)) {
07122 return vm_intro_cs(chan, vms);
07123 } else if (!strncasecmp(chan->language, "cz", 2)) {
07124 static int deprecation_warning = 0;
07125 if (deprecation_warning++ % 10 == 0) {
07126 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
07127 }
07128 return vm_intro_cs(chan, vms);
07129 } else if (!strncasecmp(chan->language, "de", 2)) {
07130 return vm_intro_de(chan, vms);
07131 } else if (!strncasecmp(chan->language, "es", 2)) {
07132 return vm_intro_es(chan, vms);
07133 } else if (!strncasecmp(chan->language, "fr", 2)) {
07134 return vm_intro_fr(chan, vms);
07135 } else if (!strncasecmp(chan->language, "gr", 2)) {
07136 return vm_intro_gr(chan, vms);
07137 } else if (!strncasecmp(chan->language, "he", 2)) {
07138 return vm_intro_he(chan, vms);
07139 } else if (!strncasecmp(chan->language, "it", 2)) {
07140 return vm_intro_it(chan, vms);
07141 } else if (!strncasecmp(chan->language, "nl", 2)) {
07142 return vm_intro_nl(chan, vms);
07143 } else if (!strncasecmp(chan->language, "no", 2)) {
07144 return vm_intro_no(chan, vms);
07145 } else if (!strncasecmp(chan->language, "pl", 2)) {
07146 return vm_intro_pl(chan, vms);
07147 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07148 return vm_intro_pt_BR(chan, vms);
07149 } else if (!strncasecmp(chan->language, "pt", 2)) {
07150 return vm_intro_pt(chan, vms);
07151 } else if (!strncasecmp(chan->language, "ru", 2)) {
07152 return vm_intro_multilang(chan, vms, "n");
07153 } else if (!strncasecmp(chan->language, "se", 2)) {
07154 return vm_intro_se(chan, vms);
07155 } else if (!strncasecmp(chan->language, "ua", 2)) {
07156 return vm_intro_multilang(chan, vms, "n");
07157 } else {
07158 return vm_intro_en(chan, vms);
07159 }
07160 }
07161
07162 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
07163 {
07164 int res = 0;
07165
07166 while (!res) {
07167 if (vms->starting) {
07168 if (vms->lastmsg > -1) {
07169 res = ast_play_and_wait(chan, "vm-onefor");
07170 if (!strncasecmp(chan->language, "he", 2)) {
07171 res = ast_play_and_wait(chan, "vm-for");
07172 }
07173 if (!res)
07174 res = vm_play_folder_name(chan, vms->vmbox);
07175 }
07176 if (!res)
07177 res = ast_play_and_wait(chan, "vm-opts");
07178 } else {
07179 if (vms->curmsg)
07180 res = ast_play_and_wait(chan, "vm-prev");
07181 if (!res && !skipadvanced)
07182 res = ast_play_and_wait(chan, "vm-advopts");
07183 if (!res)
07184 res = ast_play_and_wait(chan, "vm-repeat");
07185 if (!res && (vms->curmsg != vms->lastmsg))
07186 res = ast_play_and_wait(chan, "vm-next");
07187 if (!res) {
07188 if (!vms->deleted[vms->curmsg])
07189 res = ast_play_and_wait(chan, "vm-delete");
07190 else
07191 res = ast_play_and_wait(chan, "vm-undelete");
07192 if (!res)
07193 res = ast_play_and_wait(chan, "vm-toforward");
07194 if (!res)
07195 res = ast_play_and_wait(chan, "vm-savemessage");
07196 }
07197 }
07198 if (!res)
07199 res = ast_play_and_wait(chan, "vm-helpexit");
07200 if (!res)
07201 res = ast_waitfordigit(chan, 6000);
07202 if (!res) {
07203 vms->repeats++;
07204 if (vms->repeats > 2) {
07205 res = 't';
07206 }
07207 }
07208 }
07209 return res;
07210 }
07211
07212 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07213 {
07214 int cmd = 0;
07215 int duration = 0;
07216 int tries = 0;
07217 char newpassword[80] = "";
07218 char newpassword2[80] = "";
07219 char prefile[PATH_MAX] = "";
07220 unsigned char buf[256];
07221 int bytes=0;
07222
07223 if (ast_adsi_available(chan)) {
07224 bytes += adsi_logo(buf + bytes);
07225 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
07226 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07227 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07228 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07229 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07230 }
07231
07232
07233
07234 for (;;) {
07235 newpassword[1] = '\0';
07236 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
07237 if (cmd == '#')
07238 newpassword[0] = '\0';
07239 if (cmd < 0 || cmd == 't' || cmd == '#')
07240 return cmd;
07241 cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#");
07242 if (cmd < 0 || cmd == 't' || cmd == '#')
07243 return cmd;
07244 newpassword2[1] = '\0';
07245 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
07246 if (cmd == '#')
07247 newpassword2[0] = '\0';
07248 if (cmd < 0 || cmd == 't' || cmd == '#')
07249 return cmd;
07250 cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#");
07251 if (cmd < 0 || cmd == 't' || cmd == '#')
07252 return cmd;
07253 if (!strcmp(newpassword, newpassword2))
07254 break;
07255 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
07256 cmd = ast_play_and_wait(chan, "vm-mismatch");
07257 if (++tries == 3)
07258 return -1;
07259 if (cmd == 0) {
07260 cmd = ast_play_and_wait(chan, "vm-pls-try-again");
07261 }
07262 }
07263 if (ast_strlen_zero(ext_pass_cmd))
07264 vm_change_password(vmu,newpassword);
07265 else
07266 vm_change_password_shell(vmu,newpassword);
07267 if (option_debug > 2)
07268 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
07269 cmd = ast_play_and_wait(chan,"vm-passchanged");
07270
07271
07272 if (ast_test_flag(vmu, VM_FORCENAME)) {
07273 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
07274 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07275 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07276 if (cmd < 0 || cmd == 't' || cmd == '#')
07277 return cmd;
07278 }
07279 }
07280
07281
07282 if (ast_test_flag(vmu, VM_FORCEGREET)) {
07283 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
07284 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07285 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07286 if (cmd < 0 || cmd == 't' || cmd == '#')
07287 return cmd;
07288 }
07289
07290 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
07291 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07292 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07293 if (cmd < 0 || cmd == 't' || cmd == '#')
07294 return cmd;
07295 }
07296 }
07297
07298 return cmd;
07299 }
07300
07301 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07302 {
07303 int cmd = 0;
07304 int retries = 0;
07305 int duration = 0;
07306 char newpassword[80] = "";
07307 char newpassword2[80] = "";
07308 char prefile[PATH_MAX] = "";
07309 unsigned char buf[256];
07310 int bytes=0;
07311
07312 if (ast_adsi_available(chan))
07313 {
07314 bytes += adsi_logo(buf + bytes);
07315 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
07316 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07317 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07318 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07319 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07320 }
07321 while ((cmd >= 0) && (cmd != 't')) {
07322 if (cmd)
07323 retries = 0;
07324 switch (cmd) {
07325 case '1':
07326 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
07327 cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07328 break;
07329 case '2':
07330 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
07331 cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07332 break;
07333 case '3':
07334 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
07335 cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07336 break;
07337 case '4':
07338 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
07339 break;
07340 case '5':
07341 if (vmu->password[0] == '-') {
07342 cmd = ast_play_and_wait(chan, "vm-no");
07343 break;
07344 }
07345 newpassword[1] = '\0';
07346 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
07347 if (cmd == '#')
07348 newpassword[0] = '\0';
07349 else {
07350 if (cmd < 0)
07351 break;
07352 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
07353 break;
07354 }
07355 }
07356 newpassword2[1] = '\0';
07357 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
07358 if (cmd == '#')
07359 newpassword2[0] = '\0';
07360 else {
07361 if (cmd < 0)
07362 break;
07363
07364 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#")) < 0) {
07365 break;
07366 }
07367 }
07368 if (strcmp(newpassword, newpassword2)) {
07369 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
07370 cmd = ast_play_and_wait(chan, "vm-mismatch");
07371 if (!cmd) {
07372 cmd = ast_play_and_wait(chan, "vm-pls-try-again");
07373 }
07374 break;
07375 }
07376 if (ast_strlen_zero(ext_pass_cmd))
07377 vm_change_password(vmu,newpassword);
07378 else
07379 vm_change_password_shell(vmu,newpassword);
07380 if (option_debug > 2)
07381 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
07382 cmd = ast_play_and_wait(chan,"vm-passchanged");
07383 break;
07384 case '*':
07385 cmd = 't';
07386 break;
07387 default:
07388 cmd = 0;
07389 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07390 RETRIEVE(prefile, -1, vmu);
07391 if (ast_fileexists(prefile, NULL, NULL))
07392 cmd = ast_play_and_wait(chan, "vm-tmpexists");
07393 DISPOSE(prefile, -1);
07394 if (!cmd)
07395 cmd = ast_play_and_wait(chan, "vm-options");
07396 if (!cmd)
07397 cmd = ast_waitfordigit(chan,6000);
07398 if (!cmd)
07399 retries++;
07400 if (retries > 3)
07401 cmd = 't';
07402 }
07403 }
07404 if (cmd == 't')
07405 cmd = 0;
07406 return cmd;
07407 }
07408
07409 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07410 {
07411 int res;
07412 int cmd = 0;
07413 int retries = 0;
07414 int duration = 0;
07415 char prefile[PATH_MAX] = "";
07416 unsigned char buf[256];
07417 char dest[PATH_MAX];
07418 int bytes = 0;
07419
07420 if (ast_adsi_available(chan)) {
07421 bytes += adsi_logo(buf + bytes);
07422 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
07423 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07424 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07425 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07426 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07427 }
07428
07429 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07430 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, vms->username, "temp"))) {
07431 ast_log(LOG_WARNING, "Failed to create directory (%s).\n", prefile);
07432 return -1;
07433 }
07434 while ((cmd >= 0) && (cmd != 't')) {
07435 if (cmd)
07436 retries = 0;
07437 RETRIEVE(prefile, -1, vmu);
07438 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
07439 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07440 cmd = 't';
07441 } else {
07442 switch (cmd) {
07443 case '1':
07444 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07445 break;
07446 case '2':
07447 DELETE(prefile, -1, prefile, vmu);
07448 ast_play_and_wait(chan, "vm-tempremoved");
07449 cmd = 't';
07450 break;
07451 case '*':
07452 cmd = 't';
07453 break;
07454 default:
07455 cmd = ast_play_and_wait(chan,
07456 ast_fileexists(prefile, NULL, NULL) > 0 ?
07457 "vm-tempgreeting2" : "vm-tempgreeting");
07458 if (!cmd)
07459 cmd = ast_waitfordigit(chan,6000);
07460 if (!cmd)
07461 retries++;
07462 if (retries > 3)
07463 cmd = 't';
07464 }
07465 }
07466 DISPOSE(prefile, -1);
07467 }
07468 if (cmd == 't')
07469 cmd = 0;
07470 return cmd;
07471 }
07472
07473
07474 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07475 {
07476 int cmd=0;
07477
07478 if (vms->lastmsg > -1) {
07479 cmd = play_message(chan, vmu, vms);
07480 } else {
07481 cmd = ast_play_and_wait(chan, "vm-youhave");
07482 if (!cmd)
07483 cmd = ast_play_and_wait(chan, "vm-no");
07484 if (!cmd) {
07485 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07486 cmd = ast_play_and_wait(chan, vms->fn);
07487 }
07488 if (!cmd)
07489 cmd = ast_play_and_wait(chan, "vm-messages");
07490 }
07491 return cmd;
07492 }
07493
07494
07495 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07496 {
07497 int cmd = 0;
07498
07499 if (vms->lastmsg > -1) {
07500 cmd = play_message(chan, vmu, vms);
07501 } else {
07502 if (!strcasecmp(vms->fn, "INBOX")) {
07503 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
07504 } else {
07505 cmd = ast_play_and_wait(chan, "vm-nomessages");
07506 }
07507 }
07508 return cmd;
07509 }
07510
07511
07512 static int vm_browse_messages_latin(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07513 {
07514 int cmd=0;
07515
07516 if (vms->lastmsg > -1) {
07517 cmd = play_message(chan, vmu, vms);
07518 } else {
07519 cmd = ast_play_and_wait(chan, "vm-youhaveno");
07520 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
07521 if (!cmd) {
07522 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
07523 cmd = ast_play_and_wait(chan, vms->fn);
07524 }
07525 if (!cmd)
07526 cmd = ast_play_and_wait(chan, "vm-messages");
07527 } else {
07528 if (!cmd)
07529 cmd = ast_play_and_wait(chan, "vm-messages");
07530 if (!cmd) {
07531 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07532 cmd = ast_play_and_wait(chan, vms->fn);
07533 }
07534 }
07535 }
07536 return cmd;
07537 }
07538
07539 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07540 {
07541 if (!strncasecmp(chan->language, "es", 2) ||
07542 !strncasecmp(chan->language, "it", 2) ||
07543 !strncasecmp(chan->language, "pt", 2) ||
07544 !strncasecmp(chan->language, "gr", 2)) {
07545 return vm_browse_messages_latin(chan, vms, vmu);
07546 } else if (!strncasecmp(chan->language, "he", 2)) {
07547 return vm_browse_messages_he(chan, vms, vmu);
07548 } else {
07549 return vm_browse_messages_en(chan, vms, vmu);
07550 }
07551 }
07552
07553 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
07554 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
07555 int skipuser, int maxlogins, int silent)
07556 {
07557 int useadsi=0, valid=0, logretries=0;
07558 char password[AST_MAX_EXTENSION]="", *passptr;
07559 struct ast_vm_user vmus, *vmu = NULL;
07560
07561
07562 adsi_begin(chan, &useadsi);
07563 if (!skipuser && useadsi)
07564 adsi_login(chan);
07565 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
07566 ast_log(LOG_WARNING, "Couldn't stream login file\n");
07567 return -1;
07568 }
07569
07570
07571
07572 while (!valid && (logretries < maxlogins)) {
07573
07574 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
07575 ast_log(LOG_WARNING, "Couldn't read username\n");
07576 return -1;
07577 }
07578 if (ast_strlen_zero(mailbox)) {
07579 if (chan->cid.cid_num) {
07580 ast_copy_string(mailbox, chan->cid.cid_num, mailbox_size);
07581 } else {
07582 if (option_verbose > 2)
07583 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
07584 return -1;
07585 }
07586 }
07587 if (useadsi)
07588 adsi_password(chan);
07589
07590 if (!ast_strlen_zero(prefix)) {
07591 char fullusername[80] = "";
07592 ast_copy_string(fullusername, prefix, sizeof(fullusername));
07593 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
07594 ast_copy_string(mailbox, fullusername, mailbox_size);
07595 }
07596
07597 if (option_debug)
07598 ast_log(LOG_DEBUG, "Before find user for mailbox %s\n",mailbox);
07599 vmu = find_user(&vmus, context, mailbox);
07600 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
07601
07602 password[0] = '\0';
07603 } else {
07604 if (ast_streamfile(chan, "vm-password", chan->language)) {
07605 ast_log(LOG_WARNING, "Unable to stream password file\n");
07606 return -1;
07607 }
07608 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
07609 ast_log(LOG_WARNING, "Unable to read password\n");
07610 return -1;
07611 }
07612 }
07613
07614 if (vmu) {
07615 passptr = vmu->password;
07616 if (passptr[0] == '-') passptr++;
07617 }
07618 if (vmu && !strcmp(passptr, password))
07619 valid++;
07620 else {
07621 if (option_verbose > 2)
07622 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
07623 if (!ast_strlen_zero(prefix))
07624 mailbox[0] = '\0';
07625 }
07626 logretries++;
07627 if (!valid) {
07628 if (skipuser || logretries >= maxlogins) {
07629 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
07630 ast_log(LOG_WARNING, "Unable to stream incorrect message\n");
07631 return -1;
07632 }
07633 } else {
07634 if (useadsi)
07635 adsi_login(chan);
07636 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
07637 ast_log(LOG_WARNING, "Unable to stream incorrect mailbox message\n");
07638 return -1;
07639 }
07640 }
07641 if (ast_waitstream(chan, ""))
07642 return -1;
07643 }
07644 }
07645 if (!valid && (logretries >= maxlogins)) {
07646 ast_stopstream(chan);
07647 ast_play_and_wait(chan, "vm-goodbye");
07648 return -1;
07649 }
07650 if (vmu && !skipuser) {
07651 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
07652 }
07653 return 0;
07654 }
07655
07656 static int vm_execmain(struct ast_channel *chan, void *data)
07657 {
07658
07659
07660
07661 int res=-1;
07662 int cmd=0;
07663 int valid = 0;
07664 struct ast_module_user *u;
07665 char prefixstr[80] ="";
07666 char ext_context[256]="";
07667 int box;
07668 int useadsi = 0;
07669 int skipuser = 0;
07670 struct vm_state vms;
07671 struct ast_vm_user *vmu = NULL, vmus;
07672 char *context=NULL;
07673 int silentexit = 0;
07674 struct ast_flags flags = { 0 };
07675 signed char record_gain = 0;
07676 int play_auto = 0;
07677 int play_folder = 0;
07678 #ifdef IMAP_STORAGE
07679 int deleted = 0;
07680 #endif
07681 u = ast_module_user_add(chan);
07682
07683
07684 memset(&vms, 0, sizeof(vms));
07685 vms.lastmsg = -1;
07686
07687 memset(&vmus, 0, sizeof(vmus));
07688
07689 if (chan->_state != AST_STATE_UP) {
07690 if (option_debug)
07691 ast_log(LOG_DEBUG, "Before ast_answer\n");
07692 ast_answer(chan);
07693 }
07694
07695 if (!ast_strlen_zero(data)) {
07696 char *opts[OPT_ARG_ARRAY_SIZE];
07697 char *parse;
07698 AST_DECLARE_APP_ARGS(args,
07699 AST_APP_ARG(argv0);
07700 AST_APP_ARG(argv1);
07701 );
07702
07703 parse = ast_strdupa(data);
07704
07705 AST_STANDARD_APP_ARGS(args, parse);
07706
07707 if (args.argc == 2) {
07708 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
07709 ast_module_user_remove(u);
07710 return -1;
07711 }
07712 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
07713 int gain;
07714 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
07715 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
07716 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
07717 ast_module_user_remove(u);
07718 return -1;
07719 } else {
07720 record_gain = (signed char) gain;
07721 }
07722 } else {
07723 ast_log(LOG_WARNING, "Invalid Gain level set with option g\n");
07724 }
07725 }
07726 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
07727 play_auto = 1;
07728 if (opts[OPT_ARG_PLAYFOLDER]) {
07729 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
07730 ast_log(LOG_WARNING, "Invalid value '%s' provided for folder autoplay option\n", opts[OPT_ARG_PLAYFOLDER]);
07731 }
07732 } else {
07733 ast_log(LOG_WARNING, "Invalid folder set with option a\n");
07734 }
07735 if ( play_folder > 9 || play_folder < 0) {
07736 ast_log(LOG_WARNING, "Invalid value '%d' provided for folder autoplay option\n", play_folder);
07737 play_folder = 0;
07738 }
07739 }
07740 } else {
07741
07742 while (*(args.argv0)) {
07743 if (*(args.argv0) == 's')
07744 ast_set_flag(&flags, OPT_SILENT);
07745 else if (*(args.argv0) == 'p')
07746 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
07747 else
07748 break;
07749 (args.argv0)++;
07750 }
07751
07752 }
07753
07754 valid = ast_test_flag(&flags, OPT_SILENT);
07755
07756 if ((context = strchr(args.argv0, '@')))
07757 *context++ = '\0';
07758
07759 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
07760 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
07761 else
07762 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
07763
07764 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
07765 skipuser++;
07766 else
07767 valid = 0;
07768 }
07769
07770 if (!valid)
07771 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
07772
07773 if (option_debug)
07774 ast_log(LOG_DEBUG, "After vm_authenticate\n");
07775 if (!res) {
07776 valid = 1;
07777 if (!skipuser)
07778 vmu = &vmus;
07779 } else {
07780 res = 0;
07781 }
07782
07783
07784 adsi_begin(chan, &useadsi);
07785
07786 if (!valid) {
07787 goto out;
07788 }
07789
07790 #ifdef IMAP_STORAGE
07791 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
07792 pthread_setspecific(ts_vmstate.key, &vms);
07793
07794 vms.interactive = 1;
07795 vms.updated = 1;
07796 if (vmu)
07797 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
07798 vmstate_insert(&vms);
07799 init_vm_state(&vms);
07800 #endif
07801
07802
07803 if (!ast_strlen_zero(vmu->language))
07804 ast_string_field_set(chan, language, vmu->language);
07805 create_dirpath(vms.curdir, sizeof(vms.curdir), vmu->context, vms.username, "");
07806
07807 if (option_debug)
07808 ast_log(LOG_DEBUG, "Before open_mailbox\n");
07809 res = open_mailbox(&vms, vmu, 1);
07810 if (res < 0)
07811 goto out;
07812 vms.oldmessages = vms.lastmsg + 1;
07813 if (option_debug > 2)
07814 ast_log(LOG_DEBUG, "Number of old messages: %d\n",vms.oldmessages);
07815
07816 res = open_mailbox(&vms, vmu, 0);
07817 if (res < 0)
07818 goto out;
07819 vms.newmessages = vms.lastmsg + 1;
07820 if (option_debug > 2)
07821 ast_log(LOG_DEBUG, "Number of new messages: %d\n",vms.newmessages);
07822
07823
07824 if (play_auto) {
07825 res = open_mailbox(&vms, vmu, play_folder);
07826 if (res < 0)
07827 goto out;
07828
07829
07830 if (vms.lastmsg == -1) {
07831 cmd = vm_browse_messages(chan, &vms, vmu);
07832 res = 0;
07833 goto out;
07834 }
07835 } else {
07836 if (!vms.newmessages && vms.oldmessages) {
07837
07838 res = open_mailbox(&vms, vmu, 1);
07839 play_folder = 1;
07840 if (res < 0)
07841 goto out;
07842 }
07843 }
07844
07845 if (useadsi)
07846 adsi_status(chan, &vms);
07847 res = 0;
07848
07849
07850 if (!strcasecmp(vmu->mailbox, vmu->password) &&
07851 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
07852 if (ast_play_and_wait(chan, "vm-newuser") == -1)
07853 ast_log(LOG_WARNING, "Couldn't stream new user file\n");
07854 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
07855 if ((cmd == 't') || (cmd == '#')) {
07856
07857 res = 0;
07858 goto out;
07859 } else if (cmd < 0) {
07860
07861 res = -1;
07862 goto out;
07863 }
07864 }
07865 #ifdef IMAP_STORAGE
07866 if (option_debug > 2)
07867 ast_log(LOG_DEBUG, "Checking quotas: comparing %u to %u\n",vms.quota_usage,vms.quota_limit);
07868 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
07869 if (option_debug)
07870 ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!!\n");
07871 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
07872 }
07873 if (option_debug > 2)
07874 ast_log(LOG_DEBUG, "Checking quotas: User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
07875 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
07876 ast_log(LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
07877 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
07878 }
07879 #endif
07880 if (play_auto) {
07881 cmd = '1';
07882 } else {
07883 cmd = vm_intro(chan, vmu, &vms);
07884 }
07885
07886 vms.repeats = 0;
07887 vms.starting = 1;
07888 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
07889
07890 switch (cmd) {
07891 case '1':
07892 vms.curmsg = 0;
07893
07894 case '5':
07895 cmd = vm_browse_messages(chan, &vms, vmu);
07896 break;
07897 case '2':
07898 if (useadsi)
07899 adsi_folders(chan, 0, "Change to folder...");
07900 cmd = get_folder2(chan, "vm-changeto", 0);
07901 if (cmd == '#') {
07902 cmd = 0;
07903 } else if (cmd > 0) {
07904 cmd = cmd - '0';
07905 res = close_mailbox(&vms, vmu);
07906 if (res == ERROR_LOCK_PATH)
07907 goto out;
07908 res = open_mailbox(&vms, vmu, cmd);
07909 if (res < 0)
07910 goto out;
07911 play_folder = cmd;
07912 cmd = 0;
07913 }
07914 if (useadsi)
07915 adsi_status2(chan, &vms);
07916
07917 if (!cmd)
07918 cmd = vm_play_folder_name(chan, vms.vmbox);
07919
07920 vms.starting = 1;
07921 break;
07922 case '3':
07923 cmd = 0;
07924 vms.repeats = 0;
07925 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
07926 switch (cmd) {
07927 case '1':
07928 if (vms.lastmsg > -1 && !vms.starting) {
07929 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
07930 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
07931 res = cmd;
07932 goto out;
07933 }
07934 } else
07935 cmd = ast_play_and_wait(chan, "vm-sorry");
07936 cmd = 't';
07937 break;
07938 case '2':
07939 if (option_verbose > 2 && !vms.starting)
07940 ast_verbose( VERBOSE_PREFIX_3 "Callback Requested\n");
07941 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
07942 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
07943 if (cmd == 9) {
07944 silentexit = 1;
07945 goto out;
07946 } else if (cmd == ERROR_LOCK_PATH) {
07947 res = cmd;
07948 goto out;
07949 }
07950 }
07951 else
07952 cmd = ast_play_and_wait(chan, "vm-sorry");
07953 cmd = 't';
07954 break;
07955 case '3':
07956 if (vms.lastmsg > -1 && !vms.starting) {
07957 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
07958 if (cmd == ERROR_LOCK_PATH) {
07959 res = cmd;
07960 goto out;
07961 }
07962 } else
07963 cmd = ast_play_and_wait(chan, "vm-sorry");
07964 cmd = 't';
07965 break;
07966 case '4':
07967 if (!ast_strlen_zero(vmu->dialout)) {
07968 cmd = dialout(chan, vmu, NULL, vmu->dialout);
07969 if (cmd == 9) {
07970 silentexit = 1;
07971 goto out;
07972 }
07973 }
07974 else
07975 cmd = ast_play_and_wait(chan, "vm-sorry");
07976 cmd = 't';
07977 break;
07978
07979 case '5':
07980 if (ast_test_flag(vmu, VM_SVMAIL)) {
07981 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain);
07982 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
07983 res = cmd;
07984 goto out;
07985 }
07986 } else
07987 cmd = ast_play_and_wait(chan,"vm-sorry");
07988 cmd='t';
07989 break;
07990
07991 case '*':
07992 cmd = 't';
07993 break;
07994
07995 default:
07996 cmd = 0;
07997 if (!vms.starting) {
07998 cmd = ast_play_and_wait(chan, "vm-toreply");
07999 }
08000 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
08001 cmd = ast_play_and_wait(chan, "vm-tocallback");
08002 }
08003 if (!cmd && !vms.starting) {
08004 cmd = ast_play_and_wait(chan, "vm-tohearenv");
08005 }
08006 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
08007 cmd = ast_play_and_wait(chan, "vm-tomakecall");
08008 }
08009 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
08010 cmd=ast_play_and_wait(chan, "vm-leavemsg");
08011 if (!cmd)
08012 cmd = ast_play_and_wait(chan, "vm-starmain");
08013 if (!cmd)
08014 cmd = ast_waitfordigit(chan,6000);
08015 if (!cmd)
08016 vms.repeats++;
08017 if (vms.repeats > 3)
08018 cmd = 't';
08019 }
08020 }
08021 if (cmd == 't') {
08022 cmd = 0;
08023 vms.repeats = 0;
08024 }
08025 break;
08026 case '4':
08027 if (vms.curmsg > 0) {
08028 vms.curmsg--;
08029 cmd = play_message(chan, vmu, &vms);
08030 } else {
08031 cmd = ast_play_and_wait(chan, "vm-nomore");
08032 }
08033 break;
08034 case '6':
08035 if (vms.curmsg < vms.lastmsg) {
08036 vms.curmsg++;
08037 cmd = play_message(chan, vmu, &vms);
08038 } else {
08039 cmd = ast_play_and_wait(chan, "vm-nomore");
08040 }
08041 break;
08042 case '7':
08043 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
08044 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
08045 if (useadsi)
08046 adsi_delete(chan, &vms);
08047 if (vms.deleted[vms.curmsg]) {
08048 if (play_folder == 0)
08049 vms.newmessages--;
08050 else if (play_folder == 1)
08051 vms.oldmessages--;
08052 cmd = ast_play_and_wait(chan, "vm-deleted");
08053 }
08054 else {
08055 if (play_folder == 0)
08056 vms.newmessages++;
08057 else if (play_folder == 1)
08058 vms.oldmessages++;
08059 cmd = ast_play_and_wait(chan, "vm-undeleted");
08060 }
08061 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
08062 if (vms.curmsg < vms.lastmsg) {
08063 vms.curmsg++;
08064 cmd = play_message(chan, vmu, &vms);
08065 } else {
08066 cmd = ast_play_and_wait(chan, "vm-nomore");
08067 }
08068 }
08069 } else
08070 cmd = 0;
08071 #ifdef IMAP_STORAGE
08072 deleted = 1;
08073 #endif
08074 break;
08075
08076 case '8':
08077 if (vms.lastmsg > -1) {
08078 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain);
08079 if (cmd == ERROR_LOCK_PATH) {
08080 res = cmd;
08081 goto out;
08082 }
08083 } else
08084 cmd = ast_play_and_wait(chan, "vm-nomore");
08085 break;
08086 case '9':
08087 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
08088
08089 cmd = 0;
08090 break;
08091 }
08092 if (useadsi)
08093 adsi_folders(chan, 1, "Save to folder...");
08094 cmd = get_folder2(chan, "vm-savefolder", 1);
08095 box = 0;
08096 if (cmd == '#') {
08097 cmd = 0;
08098 break;
08099 } else if (cmd > 0) {
08100 box = cmd = cmd - '0';
08101 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
08102 if (cmd == ERROR_LOCK_PATH) {
08103 res = cmd;
08104 goto out;
08105 #ifndef IMAP_STORAGE
08106 } else if (!cmd) {
08107 vms.deleted[vms.curmsg] = 1;
08108 #endif
08109 } else {
08110 vms.deleted[vms.curmsg] = 0;
08111 vms.heard[vms.curmsg] = 0;
08112 }
08113 }
08114 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
08115 if (useadsi)
08116 adsi_message(chan, &vms);
08117 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
08118 if (!cmd) {
08119 cmd = ast_play_and_wait(chan, "vm-message");
08120 if (!cmd)
08121 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
08122 if (!cmd)
08123 cmd = ast_play_and_wait(chan, "vm-savedto");
08124 if (!cmd)
08125 cmd = vm_play_folder_name(chan, vms.fn);
08126 } else {
08127 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
08128 }
08129 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
08130 if (vms.curmsg < vms.lastmsg) {
08131 vms.curmsg++;
08132 cmd = play_message(chan, vmu, &vms);
08133 } else {
08134 cmd = ast_play_and_wait(chan, "vm-nomore");
08135 }
08136 }
08137 break;
08138 case '*':
08139 if (!vms.starting) {
08140 cmd = ast_play_and_wait(chan, "vm-onefor");
08141 if (!strncasecmp(chan->language, "he", 2)) {
08142 cmd = ast_play_and_wait(chan, "vm-for");
08143 }
08144 if (!cmd)
08145 cmd = vm_play_folder_name(chan, vms.vmbox);
08146 if (!cmd)
08147 cmd = ast_play_and_wait(chan, "vm-opts");
08148 if (!cmd)
08149 cmd = vm_instructions(chan, &vms, 1);
08150 } else
08151 cmd = 0;
08152 break;
08153 case '0':
08154 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
08155 if (useadsi)
08156 adsi_status(chan, &vms);
08157 break;
08158 default:
08159 cmd = vm_instructions(chan, &vms, 0);
08160 break;
08161 }
08162 }
08163 if ((cmd == 't') || (cmd == '#')) {
08164
08165 res = 0;
08166 } else {
08167
08168 res = -1;
08169 }
08170
08171 out:
08172 if (res > -1) {
08173 ast_stopstream(chan);
08174 adsi_goodbye(chan);
08175 if (valid && res != OPERATOR_EXIT) {
08176 if (silentexit)
08177 res = ast_play_and_wait(chan, "vm-dialout");
08178 else
08179 res = ast_play_and_wait(chan, "vm-goodbye");
08180 }
08181 if ((valid && res > 0) || res == OPERATOR_EXIT) {
08182 res = 0;
08183 }
08184 if (useadsi)
08185 ast_adsi_unload_session(chan);
08186 }
08187 if (vmu)
08188 close_mailbox(&vms, vmu);
08189 if (valid) {
08190 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
08191 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
08192 run_externnotify(vmu->context, vmu->mailbox);
08193 }
08194 #ifdef IMAP_STORAGE
08195
08196 if (option_debug > 2)
08197 ast_log(LOG_DEBUG, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted,expungeonhangup);
08198 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
08199 ast_mutex_lock(&vms.lock);
08200 #ifdef HAVE_IMAP_TK2006
08201 if (LEVELUIDPLUS (vms.mailstream)) {
08202 mail_expunge_full(vms.mailstream,NIL,EX_UID);
08203 } else
08204 #endif
08205 mail_expunge(vms.mailstream);
08206 ast_mutex_unlock(&vms.lock);
08207 }
08208
08209
08210 if (vmu) {
08211 vmstate_delete(&vms);
08212 }
08213 #endif
08214 if (vmu)
08215 free_user(vmu);
08216 if (vms.deleted)
08217 free(vms.deleted);
08218 if (vms.heard)
08219 free(vms.heard);
08220
08221 #ifdef IMAP_STORAGE
08222 pthread_setspecific(ts_vmstate.key, NULL);
08223 #endif
08224 ast_module_user_remove(u);
08225 return res;
08226 }
08227
08228 static int vm_exec(struct ast_channel *chan, void *data)
08229 {
08230 int res = 0;
08231 struct ast_module_user *u;
08232 char *tmp;
08233 struct leave_vm_options leave_options;
08234 struct ast_flags flags = { 0 };
08235 static int deprecate_warning = 0;
08236 char *opts[OPT_ARG_ARRAY_SIZE];
08237 AST_DECLARE_APP_ARGS(args,
08238 AST_APP_ARG(argv0);
08239 AST_APP_ARG(argv1);
08240 );
08241
08242 u = ast_module_user_add(chan);
08243
08244 memset(&leave_options, 0, sizeof(leave_options));
08245
08246 if (chan->_state != AST_STATE_UP)
08247 ast_answer(chan);
08248
08249 if (!ast_strlen_zero(data)) {
08250 tmp = ast_strdupa(data);
08251 AST_STANDARD_APP_ARGS(args, tmp);
08252 if (args.argc == 2) {
08253 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
08254 ast_module_user_remove(u);
08255 return -1;
08256 }
08257 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_PRIORITY_JUMP);
08258 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
08259 int gain;
08260
08261 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
08262 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
08263 ast_module_user_remove(u);
08264 return -1;
08265 } else {
08266 leave_options.record_gain = (signed char) gain;
08267 }
08268 }
08269 } else {
08270
08271 int old = 0;
08272 char *orig_argv0 = args.argv0;
08273 while (*(args.argv0)) {
08274 if (*(args.argv0) == 's') {
08275 old = 1;
08276 ast_set_flag(&leave_options, OPT_SILENT);
08277 } else if (*(args.argv0) == 'b') {
08278 old = 1;
08279 ast_set_flag(&leave_options, OPT_BUSY_GREETING);
08280 } else if (*(args.argv0) == 'u') {
08281 old = 1;
08282 ast_set_flag(&leave_options, OPT_UNAVAIL_GREETING);
08283 } else if (*(args.argv0) == 'j') {
08284 old = 1;
08285 ast_set_flag(&leave_options, OPT_PRIORITY_JUMP);
08286 } else
08287 break;
08288 (args.argv0)++;
08289 }
08290 if (!deprecate_warning && old) {
08291 deprecate_warning = 1;
08292 ast_log(LOG_WARNING, "Prefixing the mailbox with an option is deprecated ('%s').\n", orig_argv0);
08293 ast_log(LOG_WARNING, "Please move all leading options to the second argument.\n");
08294 }
08295 }
08296 } else {
08297 char tmp[256];
08298 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
08299 if (res < 0) {
08300 ast_module_user_remove(u);
08301 return res;
08302 }
08303 if (ast_strlen_zero(tmp)) {
08304 ast_module_user_remove(u);
08305 return 0;
08306 }
08307 args.argv0 = ast_strdupa(tmp);
08308 }
08309
08310 res = leave_voicemail(chan, args.argv0, &leave_options);
08311 if (res == 't') {
08312 ast_play_and_wait(chan, "vm-goodbye");
08313 res = 0;
08314 }
08315
08316 if (res == OPERATOR_EXIT) {
08317 res = 0;
08318 }
08319
08320 if (res == ERROR_LOCK_PATH) {
08321 ast_log(LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
08322
08323 if (ast_test_flag(&leave_options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
08324 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
08325 ast_log(LOG_WARNING, "Extension %s, priority %d doesn't exist.\n", chan->exten, chan->priority + 101);
08326 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
08327 res = 0;
08328 }
08329
08330 ast_module_user_remove(u);
08331
08332 return res;
08333 }
08334
08335 static struct ast_vm_user *find_or_create(char *context, char *mbox)
08336 {
08337 struct ast_vm_user *vmu;
08338 AST_LIST_TRAVERSE(&users, vmu, list) {
08339 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mbox, vmu->mailbox)) {
08340 if (strcasecmp(vmu->context, context)) {
08341 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
08342 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
08343 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
08344 \n\tamend your voicemail.conf file to avoid this situation.\n", mbox);
08345 }
08346 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", mbox);
08347 return NULL;
08348 }
08349 if (!strcasecmp(context, vmu->context) && !strcasecmp(mbox, vmu->mailbox)) {
08350 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", mbox, context);
08351 return NULL;
08352 }
08353 }
08354
08355 if ((vmu = ast_calloc(1, sizeof(*vmu)))) {
08356 ast_copy_string(vmu->context, context, sizeof(vmu->context));
08357 ast_copy_string(vmu->mailbox, mbox, sizeof(vmu->mailbox));
08358 AST_LIST_INSERT_TAIL(&users, vmu, list);
08359 }
08360 return vmu;
08361 }
08362
08363 static int append_mailbox(char *context, char *mbox, char *data)
08364 {
08365
08366 char *tmp;
08367 char *stringp;
08368 char *s;
08369 struct ast_vm_user *vmu;
08370
08371 tmp = ast_strdupa(data);
08372
08373 if ((vmu = find_or_create(context, mbox))) {
08374 populate_defaults(vmu);
08375
08376 stringp = tmp;
08377 if ((s = strsep(&stringp, ",")))
08378 ast_copy_string(vmu->password, s, sizeof(vmu->password));
08379 if (stringp && (s = strsep(&stringp, ",")))
08380 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
08381 if (stringp && (s = strsep(&stringp, ",")))
08382 ast_copy_string(vmu->email, s, sizeof(vmu->email));
08383 if (stringp && (s = strsep(&stringp, ",")))
08384 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
08385 if (stringp && (s = strsep(&stringp, ",")))
08386 apply_options(vmu, s);
08387 }
08388 return 0;
08389 }
08390
08391 static int vm_box_exists(struct ast_channel *chan, void *data)
08392 {
08393 struct ast_module_user *u;
08394 struct ast_vm_user svm;
08395 char *context, *box;
08396 int priority_jump = 0;
08397 AST_DECLARE_APP_ARGS(args,
08398 AST_APP_ARG(mbox);
08399 AST_APP_ARG(options);
08400 );
08401
08402 if (ast_strlen_zero(data)) {
08403 ast_log(LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
08404 return -1;
08405 }
08406
08407 u = ast_module_user_add(chan);
08408
08409 box = ast_strdupa(data);
08410
08411 AST_STANDARD_APP_ARGS(args, box);
08412
08413 if (args.options) {
08414 if (strchr(args.options, 'j'))
08415 priority_jump = 1;
08416 }
08417
08418 if ((context = strchr(args.mbox, '@'))) {
08419 *context = '\0';
08420 context++;
08421 }
08422
08423 if (find_user(&svm, context, args.mbox)) {
08424 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
08425 if (priority_jump || ast_opt_priority_jumping)
08426 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
08427 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);
08428 } else
08429 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
08430 ast_module_user_remove(u);
08431 return 0;
08432 }
08433
08434 static int vmauthenticate(struct ast_channel *chan, void *data)
08435 {
08436 struct ast_module_user *u;
08437 char *s = data, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION] = "";
08438 struct ast_vm_user vmus;
08439 char *options = NULL;
08440 int silent = 0, skipuser = 0;
08441 int res = -1;
08442
08443 u = ast_module_user_add(chan);
08444
08445 if (s) {
08446 s = ast_strdupa(s);
08447 user = strsep(&s, "|");
08448 options = strsep(&s, "|");
08449 if (user) {
08450 s = user;
08451 user = strsep(&s, "@");
08452 context = strsep(&s, "");
08453 if (!ast_strlen_zero(user))
08454 skipuser++;
08455 ast_copy_string(mailbox, user, sizeof(mailbox));
08456 }
08457 }
08458
08459 if (options) {
08460 silent = (strchr(options, 's')) != NULL;
08461 }
08462
08463 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
08464 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
08465 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
08466 ast_play_and_wait(chan, "auth-thankyou");
08467 res = 0;
08468 }
08469
08470 ast_module_user_remove(u);
08471 return res;
08472 }
08473
08474 static char voicemail_show_users_help[] =
08475 "Usage: voicemail show users [for <context>]\n"
08476 " Lists all mailboxes currently set up\n";
08477
08478 static char voicemail_show_zones_help[] =
08479 "Usage: voicemail show zones\n"
08480 " Lists zone message formats\n";
08481
08482 static int handle_voicemail_show_users(int fd, int argc, char *argv[])
08483 {
08484 struct ast_vm_user *vmu;
08485 char *output_format = "%-10s %-5s %-25s %-10s %6s\n";
08486
08487 if ((argc < 3) || (argc > 5) || (argc == 4)) return RESULT_SHOWUSAGE;
08488 else if ((argc == 5) && strcmp(argv[3],"for")) return RESULT_SHOWUSAGE;
08489
08490 AST_LIST_LOCK(&users);
08491 if (!AST_LIST_EMPTY(&users)) {
08492 if (argc == 3)
08493 ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
08494 else {
08495 int count = 0;
08496 AST_LIST_TRAVERSE(&users, vmu, list) {
08497 if (!strcmp(argv[4],vmu->context))
08498 count++;
08499 }
08500 if (count) {
08501 ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
08502 } else {
08503 ast_cli(fd, "No such voicemail context \"%s\"\n", argv[4]);
08504 AST_LIST_UNLOCK(&users);
08505 return RESULT_FAILURE;
08506 }
08507 }
08508 AST_LIST_TRAVERSE(&users, vmu, list) {
08509 int newmsgs = 0, oldmsgs = 0;
08510 char count[12], tmp[256] = "";
08511
08512 if ((argc == 3) || ((argc == 5) && !strcmp(argv[4],vmu->context))) {
08513 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
08514 inboxcount(tmp, &newmsgs, &oldmsgs);
08515 snprintf(count,sizeof(count),"%d",newmsgs);
08516 ast_cli(fd, output_format, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
08517 }
08518 }
08519 } else {
08520 ast_cli(fd, "There are no voicemail users currently defined\n");
08521 AST_LIST_UNLOCK(&users);
08522 return RESULT_FAILURE;
08523 }
08524 AST_LIST_UNLOCK(&users);
08525 return RESULT_SUCCESS;
08526 }
08527
08528 static int handle_voicemail_show_zones(int fd, int argc, char *argv[])
08529 {
08530 struct vm_zone *zone;
08531 char *output_format = "%-15s %-20s %-45s\n";
08532 int res = RESULT_SUCCESS;
08533
08534 if (argc != 3)
08535 return RESULT_SHOWUSAGE;
08536
08537 AST_LIST_LOCK(&zones);
08538 if (!AST_LIST_EMPTY(&zones)) {
08539 ast_cli(fd, output_format, "Zone", "Timezone", "Message Format");
08540 AST_LIST_TRAVERSE(&zones, zone, list) {
08541 ast_cli(fd, output_format, zone->name, zone->timezone, zone->msg_format);
08542 }
08543 } else {
08544 ast_cli(fd, "There are no voicemail zones currently defined\n");
08545 res = RESULT_FAILURE;
08546 }
08547 AST_LIST_UNLOCK(&zones);
08548
08549 return res;
08550 }
08551
08552 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
08553 {
08554 int which = 0;
08555 int wordlen;
08556 struct ast_vm_user *vmu;
08557 const char *context = "";
08558
08559
08560 if (pos > 4)
08561 return NULL;
08562 if (pos == 3)
08563 return (state == 0) ? ast_strdup("for") : NULL;
08564 wordlen = strlen(word);
08565 AST_LIST_TRAVERSE(&users, vmu, list) {
08566 if (!strncasecmp(word, vmu->context, wordlen)) {
08567 if (context && strcmp(context, vmu->context) && ++which > state)
08568 return ast_strdup(vmu->context);
08569
08570 context = vmu->context;
08571 }
08572 }
08573 return NULL;
08574 }
08575
08576 static struct ast_cli_entry cli_show_voicemail_users_deprecated = {
08577 { "show", "voicemail", "users", NULL },
08578 handle_voicemail_show_users, NULL,
08579 NULL, complete_voicemail_show_users };
08580
08581 static struct ast_cli_entry cli_show_voicemail_zones_deprecated = {
08582 { "show", "voicemail", "zones", NULL },
08583 handle_voicemail_show_zones, NULL,
08584 NULL, NULL };
08585
08586 static struct ast_cli_entry cli_voicemail[] = {
08587 { { "voicemail", "show", "users", NULL },
08588 handle_voicemail_show_users, "List defined voicemail boxes",
08589 voicemail_show_users_help, complete_voicemail_show_users, &cli_show_voicemail_users_deprecated },
08590
08591 { { "voicemail", "show", "zones", NULL },
08592 handle_voicemail_show_zones, "List zone message formats",
08593 voicemail_show_zones_help, NULL, &cli_show_voicemail_zones_deprecated },
08594 };
08595
08596 static void free_vm_users(void)
08597 {
08598 struct ast_vm_user *cur;
08599 struct vm_zone *zcur;
08600
08601 AST_LIST_LOCK(&users);
08602 while ((cur = AST_LIST_REMOVE_HEAD(&users, list))) {
08603 ast_set_flag(cur, VM_ALLOCED);
08604 free_user(cur);
08605 }
08606 AST_LIST_UNLOCK(&users);
08607
08608 AST_LIST_LOCK(&zones);
08609 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list))) {
08610 free_zone(zcur);
08611 }
08612 AST_LIST_UNLOCK(&zones);
08613 }
08614
08615 static int load_config(void)
08616 {
08617 struct ast_vm_user *cur;
08618 struct ast_config *cfg, *ucfg;
08619 char *cat;
08620 struct ast_variable *var;
08621 const char *notifystr = NULL;
08622 const char *smdistr = NULL;
08623 const char *astattach;
08624 const char *astsearch;
08625 const char *astsaycid;
08626 const char *send_voicemail;
08627 #ifdef IMAP_STORAGE
08628 const char *imap_server;
08629 const char *imap_port;
08630 const char *imap_flags;
08631 const char *imap_folder;
08632 const char *auth_user;
08633 const char *auth_password;
08634 const char *expunge_on_hangup;
08635 const char *imap_timeout;
08636 #endif
08637 const char *astcallop;
08638 const char *astreview;
08639 const char *asttempgreetwarn;
08640 const char *astskipcmd;
08641 const char *asthearenv;
08642 const char *astsaydurationinfo;
08643 const char *astsaydurationminfo;
08644 const char *silencestr;
08645 const char *maxmsgstr;
08646 const char *astdirfwd;
08647 const char *thresholdstr;
08648 const char *fmt;
08649 const char *astemail;
08650 const char *ucontext;
08651 const char *astmailcmd = SENDMAIL;
08652 const char *astpreprocesscmd;
08653 const char *astpreprocessfmt;
08654 const char *astforcename;
08655 const char *astforcegreet;
08656 const char *s;
08657 char *q,*stringp, *tmp;
08658 const char *dialoutcxt = NULL;
08659 const char *callbackcxt = NULL;
08660 const char *exitcxt = NULL;
08661 const char *extpc;
08662 const char *emaildateformatstr;
08663 const char *volgainstr;
08664 int x;
08665 int tmpadsi[4];
08666
08667 cfg = ast_config_load(VOICEMAIL_CONFIG);
08668
08669 free_vm_users();
08670
08671 AST_LIST_LOCK(&users);
08672
08673 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
08674
08675 if (cfg) {
08676
08677
08678 if (!(ucontext = ast_variable_retrieve(cfg, "general", "userscontext")))
08679 ucontext = "default";
08680 ast_copy_string(userscontext, ucontext, sizeof(userscontext));
08681
08682 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
08683 astattach = "yes";
08684 ast_set2_flag((&globalflags), ast_true(astattach), VM_ATTACH);
08685
08686 if (!(astsearch = ast_variable_retrieve(cfg, "general", "searchcontexts")))
08687 astsearch = "no";
08688 ast_set2_flag((&globalflags), ast_true(astsearch), VM_SEARCH);
08689
08690 volgain = 0.0;
08691 if ((volgainstr = ast_variable_retrieve(cfg, "general", "volgain")))
08692 sscanf(volgainstr, "%30lf", &volgain);
08693
08694 #ifdef ODBC_STORAGE
08695 strcpy(odbc_database, "asterisk");
08696 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
08697 ast_copy_string(odbc_database, thresholdstr, sizeof(odbc_database));
08698 }
08699 strcpy(odbc_table, "voicemessages");
08700 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbctable"))) {
08701 ast_copy_string(odbc_table, thresholdstr, sizeof(odbc_table));
08702 }
08703 #endif
08704
08705 strcpy(mailcmd, SENDMAIL);
08706 if ((astmailcmd = ast_variable_retrieve(cfg, "general", "mailcmd")))
08707 ast_copy_string(mailcmd, astmailcmd, sizeof(mailcmd));
08708
08709 if ((astpreprocesscmd = ast_variable_retrieve(cfg, "general", "preprocesscmd")))
08710 ast_copy_string(preprocesscmd, astpreprocesscmd, sizeof(preprocesscmd));
08711
08712 if ((astpreprocessfmt = ast_variable_retrieve(cfg, "general", "preprocessfmt")))
08713 ast_copy_string(preprocessfmt, astpreprocessfmt, sizeof(preprocessfmt));
08714
08715 maxsilence = 0;
08716 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
08717 maxsilence = atoi(silencestr);
08718 if (maxsilence > 0)
08719 maxsilence *= 1000;
08720 }
08721
08722 if (!(maxmsgstr = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
08723 maxmsg = MAXMSG;
08724 } else {
08725 maxmsg = atoi(maxmsgstr);
08726 if (maxmsg <= 0) {
08727 ast_log(LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", maxmsgstr, MAXMSG);
08728 maxmsg = MAXMSG;
08729 } else if (maxmsg > MAXMSGLIMIT) {
08730 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, maxmsgstr);
08731 maxmsg = MAXMSGLIMIT;
08732 }
08733 }
08734
08735
08736 if ((emaildateformatstr = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
08737 ast_copy_string(emaildateformat, emaildateformatstr, sizeof(emaildateformat));
08738 }
08739
08740
08741 if ((extpc = ast_variable_retrieve(cfg, "general", "externpass"))) {
08742 ast_copy_string(ext_pass_cmd,extpc,sizeof(ext_pass_cmd));
08743 }
08744 #ifdef IMAP_STORAGE
08745
08746 if ((imap_server = ast_variable_retrieve(cfg, "general", "imapserver"))) {
08747 ast_copy_string(imapserver, imap_server, sizeof(imapserver));
08748 } else {
08749 ast_copy_string(imapserver,"localhost", sizeof(imapserver));
08750 }
08751
08752 if ((imap_port = ast_variable_retrieve(cfg, "general", "imapport"))) {
08753 ast_copy_string(imapport, imap_port, sizeof(imapport));
08754 } else {
08755 ast_copy_string(imapport,"143", sizeof(imapport));
08756 }
08757
08758 if ((imap_flags = ast_variable_retrieve(cfg, "general", "imapflags"))) {
08759 ast_copy_string(imapflags, imap_flags, sizeof(imapflags));
08760 }
08761
08762 if ((auth_user = ast_variable_retrieve(cfg, "general", "authuser"))) {
08763 ast_copy_string(authuser, auth_user, sizeof(authuser));
08764 }
08765
08766 if ((auth_password = ast_variable_retrieve(cfg, "general", "authpassword"))) {
08767 ast_copy_string(authpassword, auth_password, sizeof(authpassword));
08768 }
08769
08770 if ((expunge_on_hangup = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
08771 if (ast_false(expunge_on_hangup))
08772 expungeonhangup = 0;
08773 else
08774 expungeonhangup = 1;
08775 } else {
08776 expungeonhangup = 1;
08777 }
08778
08779 if ((imap_folder = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
08780 ast_copy_string(imapfolder, imap_folder, sizeof(imapfolder));
08781 } else {
08782 ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
08783 }
08784
08785
08786
08787
08788
08789
08790 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
08791 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(imap_timeout)));
08792 } else {
08793 mail_parameters(NIL, SET_READTIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08794 }
08795
08796 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
08797 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(imap_timeout)));
08798 } else {
08799 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08800 }
08801
08802 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
08803 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(imap_timeout)));
08804 } else {
08805 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08806 }
08807
08808 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
08809 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(imap_timeout)));
08810 } else {
08811 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08812 }
08813
08814
08815 imapversion++;
08816 #endif
08817
08818
08819 if ((notifystr = ast_variable_retrieve(cfg, "general", "externnotify"))) {
08820 ast_copy_string(externnotify, notifystr, sizeof(externnotify));
08821 if (option_debug > 2)
08822 ast_log(LOG_DEBUG, "found externnotify: %s\n", externnotify);
08823 if (!strcasecmp(externnotify, "smdi")) {
08824 if (option_debug)
08825 ast_log(LOG_DEBUG, "Using SMDI for external voicemail notification\n");
08826 if ((smdistr = ast_variable_retrieve(cfg, "general", "smdiport"))) {
08827 smdi_iface = ast_smdi_interface_find(smdistr);
08828 } else {
08829 if (option_debug)
08830 ast_log(LOG_DEBUG, "No SMDI interface set, trying default (/dev/ttyS0)\n");
08831 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
08832 }
08833
08834 if (!smdi_iface) {
08835 ast_log(LOG_ERROR, "No valid SMDI interface specfied, disabling external voicemail notification\n");
08836 externnotify[0] = '\0';
08837 }
08838 }
08839 } else {
08840 externnotify[0] = '\0';
08841 }
08842
08843
08844 silencethreshold = 256;
08845 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
08846 silencethreshold = atoi(thresholdstr);
08847
08848 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
08849 astemail = ASTERISK_USERNAME;
08850 ast_copy_string(serveremail, astemail, sizeof(serveremail));
08851
08852 vmmaxmessage = 0;
08853 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
08854 if (sscanf(s, "%30d", &x) == 1) {
08855 vmmaxmessage = x;
08856 } else {
08857 ast_log(LOG_WARNING, "Invalid max message time length\n");
08858 }
08859 }
08860
08861 vmminmessage = 0;
08862 if ((s = ast_variable_retrieve(cfg, "general", "minmessage"))) {
08863 if (sscanf(s, "%30d", &x) == 1) {
08864 vmminmessage = x;
08865 if (maxsilence / 1000 >= vmminmessage)
08866 ast_log(LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
08867 } else {
08868 ast_log(LOG_WARNING, "Invalid min message time length\n");
08869 }
08870 }
08871 fmt = ast_variable_retrieve(cfg, "general", "format");
08872 if (!fmt) {
08873 fmt = "wav";
08874 } else {
08875 tmp = ast_strdupa(fmt);
08876 fmt = ast_format_str_reduce(tmp);
08877 if (!fmt) {
08878 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
08879 fmt = "wav";
08880 }
08881 }
08882
08883 ast_copy_string(vmfmts, fmt, sizeof(vmfmts));
08884
08885 skipms = 3000;
08886 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
08887 if (sscanf(s, "%30d", &x) == 1) {
08888 maxgreet = x;
08889 } else {
08890 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
08891 }
08892 }
08893
08894 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
08895 if (sscanf(s, "%30d", &x) == 1) {
08896 skipms = x;
08897 } else {
08898 ast_log(LOG_WARNING, "Invalid skipms value\n");
08899 }
08900 }
08901
08902 maxlogins = 3;
08903 if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
08904 if (sscanf(s, "%30d", &x) == 1) {
08905 maxlogins = x;
08906 } else {
08907 ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
08908 }
08909 }
08910
08911
08912 if (!(astforcename = ast_variable_retrieve(cfg, "general", "forcename")))
08913 astforcename = "no";
08914 ast_set2_flag((&globalflags), ast_true(astforcename), VM_FORCENAME);
08915
08916
08917 if (!(astforcegreet = ast_variable_retrieve(cfg, "general", "forcegreetings")))
08918 astforcegreet = "no";
08919 ast_set2_flag((&globalflags), ast_true(astforcegreet), VM_FORCEGREET);
08920
08921 if ((s = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))){
08922 if (option_debug > 2)
08923 ast_log(LOG_DEBUG,"VM_CID Internal context string: %s\n",s);
08924 stringp = ast_strdupa(s);
08925 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
08926 if (!ast_strlen_zero(stringp)) {
08927 q = strsep(&stringp,",");
08928 while ((*q == ' ')||(*q == '\t'))
08929 q++;
08930 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
08931 if (option_debug > 2)
08932 ast_log(LOG_DEBUG,"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
08933 } else {
08934 cidinternalcontexts[x][0] = '\0';
08935 }
08936 }
08937 }
08938 if (!(astreview = ast_variable_retrieve(cfg, "general", "review"))){
08939 if (option_debug)
08940 ast_log(LOG_DEBUG,"VM Review Option disabled globally\n");
08941 astreview = "no";
08942 }
08943 ast_set2_flag((&globalflags), ast_true(astreview), VM_REVIEW);
08944
08945
08946 if (!(asttempgreetwarn = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
08947 if (option_debug)
08948 ast_log(LOG_DEBUG, "VM Temperary Greeting Reminder Option disabled globally\n");
08949 asttempgreetwarn = "no";
08950 } else {
08951 if (option_debug)
08952 ast_log(LOG_DEBUG, "VM Temperary Greeting Reminder Option enabled globally\n");
08953 }
08954 ast_set2_flag((&globalflags), ast_true(asttempgreetwarn), VM_TEMPGREETWARN);
08955
08956 if (!(astcallop = ast_variable_retrieve(cfg, "general", "operator"))){
08957 if (option_debug)
08958 ast_log(LOG_DEBUG,"VM Operator break disabled globally\n");
08959 astcallop = "no";
08960 }
08961 ast_set2_flag((&globalflags), ast_true(astcallop), VM_OPERATOR);
08962
08963 if (!(astsaycid = ast_variable_retrieve(cfg, "general", "saycid"))) {
08964 if (option_debug)
08965 ast_log(LOG_DEBUG,"VM CID Info before msg disabled globally\n");
08966 astsaycid = "no";
08967 }
08968 ast_set2_flag((&globalflags), ast_true(astsaycid), VM_SAYCID);
08969
08970 if (!(send_voicemail = ast_variable_retrieve(cfg,"general", "sendvoicemail"))){
08971 if (option_debug)
08972 ast_log(LOG_DEBUG,"Send Voicemail msg disabled globally\n");
08973 send_voicemail = "no";
08974 }
08975 ast_set2_flag((&globalflags), ast_true(send_voicemail), VM_SVMAIL);
08976
08977 if (!(asthearenv = ast_variable_retrieve(cfg, "general", "envelope"))) {
08978 if (option_debug)
08979 ast_log(LOG_DEBUG,"ENVELOPE before msg enabled globally\n");
08980 asthearenv = "yes";
08981 }
08982 ast_set2_flag((&globalflags), ast_true(asthearenv), VM_ENVELOPE);
08983
08984 if (!(astsaydurationinfo = ast_variable_retrieve(cfg, "general", "sayduration"))) {
08985 if (option_debug)
08986 ast_log(LOG_DEBUG,"Duration info before msg enabled globally\n");
08987 astsaydurationinfo = "yes";
08988 }
08989 ast_set2_flag((&globalflags), ast_true(astsaydurationinfo), VM_SAYDURATION);
08990
08991 saydurationminfo = 2;
08992 if ((astsaydurationminfo = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
08993 if (sscanf(astsaydurationminfo, "%30d", &x) == 1) {
08994 saydurationminfo = x;
08995 } else {
08996 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
08997 }
08998 }
08999
09000 if (!(astskipcmd = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
09001 if (option_debug)
09002 ast_log(LOG_DEBUG,"We are not going to skip to the next msg after save/delete\n");
09003 astskipcmd = "no";
09004 }
09005 ast_set2_flag((&globalflags), ast_true(astskipcmd), VM_SKIPAFTERCMD);
09006
09007 if ((dialoutcxt = ast_variable_retrieve(cfg, "general", "dialout"))) {
09008 ast_copy_string(dialcontext, dialoutcxt, sizeof(dialcontext));
09009 if (option_debug)
09010 ast_log(LOG_DEBUG, "found dialout context: %s\n", dialcontext);
09011 } else {
09012 dialcontext[0] = '\0';
09013 }
09014
09015 if ((callbackcxt = ast_variable_retrieve(cfg, "general", "callback"))) {
09016 ast_copy_string(callcontext, callbackcxt, sizeof(callcontext));
09017 if (option_debug)
09018 ast_log(LOG_DEBUG, "found callback context: %s\n", callcontext);
09019 } else {
09020 callcontext[0] = '\0';
09021 }
09022
09023 if ((exitcxt = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
09024 ast_copy_string(exitcontext, exitcxt, sizeof(exitcontext));
09025 if (option_debug)
09026 ast_log(LOG_DEBUG, "found operator context: %s\n", exitcontext);
09027 } else {
09028 exitcontext[0] = '\0';
09029 }
09030
09031 if (!(astdirfwd = ast_variable_retrieve(cfg, "general", "usedirectory")))
09032 astdirfwd = "no";
09033 ast_set2_flag((&globalflags), ast_true(astdirfwd), VM_DIRECFORWARD);
09034 if ((ucfg = ast_config_load("users.conf"))) {
09035 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
09036 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
09037 continue;
09038 if ((cur = find_or_create(userscontext, cat))) {
09039 populate_defaults(cur);
09040 apply_options_full(cur, ast_variable_browse(ucfg, cat));
09041 ast_copy_string(cur->context, userscontext, sizeof(cur->context));
09042 }
09043 }
09044 ast_config_destroy(ucfg);
09045 }
09046 cat = ast_category_browse(cfg, NULL);
09047 while (cat) {
09048 if (strcasecmp(cat, "general")) {
09049 var = ast_variable_browse(cfg, cat);
09050 if (strcasecmp(cat, "zonemessages")) {
09051
09052 while (var) {
09053 append_mailbox(cat, var->name, var->value);
09054 var = var->next;
09055 }
09056 } else {
09057
09058 while (var) {
09059 struct vm_zone *z;
09060 if ((z = ast_malloc(sizeof(*z)))) {
09061 char *msg_format, *timezone;
09062 msg_format = ast_strdupa(var->value);
09063 timezone = strsep(&msg_format, "|");
09064 if (msg_format) {
09065 ast_copy_string(z->name, var->name, sizeof(z->name));
09066 ast_copy_string(z->timezone, timezone, sizeof(z->timezone));
09067 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
09068 AST_LIST_LOCK(&zones);
09069 AST_LIST_INSERT_HEAD(&zones, z, list);
09070 AST_LIST_UNLOCK(&zones);
09071 } else {
09072 ast_log(LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
09073 free(z);
09074 }
09075 } else {
09076 free(z);
09077 AST_LIST_UNLOCK(&users);
09078 ast_config_destroy(cfg);
09079 return -1;
09080 }
09081 var = var->next;
09082 }
09083 }
09084 }
09085 cat = ast_category_browse(cfg, cat);
09086 }
09087 memset(fromstring,0,sizeof(fromstring));
09088 memset(pagerfromstring,0,sizeof(pagerfromstring));
09089 memset(emailtitle,0,sizeof(emailtitle));
09090 strcpy(charset, "ISO-8859-1");
09091 if (emailbody) {
09092 free(emailbody);
09093 emailbody = NULL;
09094 }
09095 if (emailsubject) {
09096 free(emailsubject);
09097 emailsubject = NULL;
09098 }
09099 if (pagerbody) {
09100 free(pagerbody);
09101 pagerbody = NULL;
09102 }
09103 if (pagersubject) {
09104 free(pagersubject);
09105 pagersubject = NULL;
09106 }
09107 if ((s = ast_variable_retrieve(cfg, "general", "pbxskip")))
09108 ast_set2_flag((&globalflags), ast_true(s), VM_PBXSKIP);
09109 if ((s = ast_variable_retrieve(cfg, "general", "fromstring")))
09110 ast_copy_string(fromstring,s,sizeof(fromstring));
09111 if ((s = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
09112 ast_copy_string(pagerfromstring,s,sizeof(pagerfromstring));
09113 if ((s = ast_variable_retrieve(cfg, "general", "charset")))
09114 ast_copy_string(charset,s,sizeof(charset));
09115 if ((s = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
09116 sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
09117 for (x = 0; x < 4; x++) {
09118 memcpy(&adsifdn[x], &tmpadsi[x], 1);
09119 }
09120 }
09121 if ((s = ast_variable_retrieve(cfg, "general", "adsisec"))) {
09122 sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
09123 for (x = 0; x < 4; x++) {
09124 memcpy(&adsisec[x], &tmpadsi[x], 1);
09125 }
09126 }
09127 if ((s = ast_variable_retrieve(cfg, "general", "adsiver")))
09128 if (atoi(s)) {
09129 adsiver = atoi(s);
09130 }
09131 if ((s = ast_variable_retrieve(cfg, "general", "emailtitle"))) {
09132 ast_log(LOG_NOTICE, "Keyword 'emailtitle' is DEPRECATED, please use 'emailsubject' instead.\n");
09133 ast_copy_string(emailtitle,s,sizeof(emailtitle));
09134 }
09135 if ((s = ast_variable_retrieve(cfg, "general", "emailsubject")))
09136 emailsubject = ast_strdup(s);
09137 if ((s = ast_variable_retrieve(cfg, "general", "emailbody"))) {
09138 char *tmpread, *tmpwrite;
09139 emailbody = ast_strdup(s);
09140
09141
09142 tmpread = tmpwrite = emailbody;
09143 while ((tmpwrite = strchr(tmpread,'\\'))) {
09144 switch (tmpwrite[1]) {
09145 case 'r':
09146 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09147 *tmpwrite = '\r';
09148 break;
09149 case 'n':
09150 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09151 *tmpwrite = '\n';
09152 break;
09153 case 't':
09154 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09155 *tmpwrite = '\t';
09156 break;
09157 default:
09158 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
09159 }
09160 tmpread = tmpwrite + 1;
09161 }
09162 }
09163 if ((s = ast_variable_retrieve(cfg, "general", "tz"))) {
09164 ast_copy_string(zonetag, s, sizeof(zonetag));
09165 }
09166 if ((s = ast_variable_retrieve(cfg, "general", "pagersubject")))
09167 pagersubject = ast_strdup(s);
09168 if ((s = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
09169 char *tmpread, *tmpwrite;
09170 pagerbody = ast_strdup(s);
09171
09172
09173 tmpread = tmpwrite = pagerbody;
09174 while ((tmpwrite = strchr(tmpread, '\\'))) {
09175 switch (tmpwrite[1]) {
09176 case 'r':
09177 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09178 *tmpwrite = '\r';
09179 break;
09180 case 'n':
09181 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09182 *tmpwrite = '\n';
09183 break;
09184 case 't':
09185 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
09186 *tmpwrite = '\t';
09187 break;
09188 default:
09189 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
09190 }
09191 tmpread = tmpwrite + 1;
09192 }
09193 }
09194 AST_LIST_UNLOCK(&users);
09195 ast_config_destroy(cfg);
09196 return 0;
09197 } else {
09198 AST_LIST_UNLOCK(&users);
09199 ast_log(LOG_WARNING, "Failed to load configuration file.\n");
09200 return 0;
09201 }
09202 }
09203
09204 static int reload(void)
09205 {
09206 return(load_config());
09207 }
09208
09209 static int unload_module(void)
09210 {
09211 int res;
09212
09213 res = ast_unregister_application(app);
09214 res |= ast_unregister_application(app2);
09215 res |= ast_unregister_application(app3);
09216 res |= ast_unregister_application(app4);
09217 ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
09218 ast_uninstall_vm_functions();
09219 ao2_ref(inprocess_container, -1);
09220
09221 ast_module_user_hangup_all();
09222
09223 return res;
09224 }
09225
09226 static int load_module(void)
09227 {
09228 int res;
09229 char *adsi_loaded = ast_module_helper("", "res_adsi", 0, 0, 0, 0);
09230 char *smdi_loaded = ast_module_helper("", "res_smdi", 0, 0, 0, 0);
09231 free(adsi_loaded);
09232 free(smdi_loaded);
09233
09234 if (!adsi_loaded) {
09235 ast_log(LOG_ERROR, "app_voicemail.so depends upon res_adsi.so\n");
09236 return AST_MODULE_LOAD_DECLINE;
09237 }
09238
09239 if (!smdi_loaded) {
09240 ast_log(LOG_ERROR, "app_voicemail.so depends upon res_smdi.so\n");
09241 return AST_MODULE_LOAD_DECLINE;
09242 }
09243
09244 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
09245 return AST_MODULE_LOAD_DECLINE;
09246 }
09247
09248 my_umask = umask(0);
09249 umask(my_umask);
09250 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
09251 res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
09252 res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
09253 res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate);
09254 if (res)
09255 return(res);
09256
09257 if ((res=load_config())) {
09258 return(res);
09259 }
09260
09261 ast_cli_register_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
09262
09263
09264 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
09265
09266 ast_install_vm_functions(has_voicemail, inboxcount, messagecount);
09267
09268 return res;
09269 }
09270
09271 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
09272 {
09273 int cmd = 0;
09274 char destination[80] = "";
09275 int retries = 0;
09276
09277 if (!num) {
09278 if (option_verbose > 2)
09279 ast_verbose( VERBOSE_PREFIX_3 "Destination number will be entered manually\n");
09280 while (retries < 3 && cmd != 't') {
09281 destination[1] = '\0';
09282 destination[0] = cmd = ast_play_and_wait(chan,"vm-enter-num-to-call");
09283 if (!cmd)
09284 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
09285 if (!cmd)
09286 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
09287 if (!cmd) {
09288 cmd = ast_waitfordigit(chan, 6000);
09289 if (cmd)
09290 destination[0] = cmd;
09291 }
09292 if (!cmd) {
09293 retries++;
09294 } else {
09295
09296 if (cmd < 0)
09297 return 0;
09298 if (cmd == '*') {
09299 if (option_verbose > 2)
09300 ast_verbose( VERBOSE_PREFIX_3 "User hit '*' to cancel outgoing call\n");
09301 return 0;
09302 }
09303 if ((cmd = ast_readstring(chan,destination + strlen(destination),sizeof(destination)-1,6000,10000,"#")) < 0)
09304 retries++;
09305 else
09306 cmd = 't';
09307 }
09308 }
09309 if (retries >= 3) {
09310 return 0;
09311 }
09312
09313 } else {
09314 if (option_verbose > 2)
09315 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
09316 ast_copy_string(destination, num, sizeof(destination));
09317 }
09318
09319 if (!ast_strlen_zero(destination)) {
09320 if (destination[strlen(destination) -1 ] == '*')
09321 return 0;
09322 if (option_verbose > 2)
09323 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
09324 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
09325 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
09326 chan->priority = 0;
09327 return 9;
09328 }
09329 return 0;
09330 }
09331
09332 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)
09333 {
09334 int res = 0;
09335 char filename[PATH_MAX];
09336 struct ast_config *msg_cfg = NULL;
09337 const char *origtime, *context;
09338 char *cid, *name, *num;
09339 int retries = 0;
09340
09341 vms->starting = 0;
09342 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
09343
09344
09345 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
09346 snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
09347 RETRIEVE(vms->curdir, vms->curmsg, vmu);
09348 msg_cfg = ast_config_load(filename);
09349 DISPOSE(vms->curdir, vms->curmsg);
09350 if (!msg_cfg) {
09351 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
09352 return 0;
09353 }
09354
09355 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
09356 ast_config_destroy(msg_cfg);
09357 return 0;
09358 }
09359
09360 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
09361
09362 context = ast_variable_retrieve(msg_cfg, "message", "context");
09363 if (!strncasecmp("macro",context,5))
09364 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
09365 switch (option) {
09366 case 3:
09367 if (!res)
09368 res = play_message_datetime(chan, vmu, origtime, filename);
09369 if (!res)
09370 res = play_message_callerid(chan, vms, cid, context, 0);
09371
09372 res = 't';
09373 break;
09374
09375 case 2:
09376
09377 if (ast_strlen_zero(cid))
09378 break;
09379
09380 ast_callerid_parse(cid, &name, &num);
09381 while ((res > -1) && (res != 't')) {
09382 switch (res) {
09383 case '1':
09384 if (num) {
09385
09386 res = dialout(chan, vmu, num, vmu->callback);
09387 if (res) {
09388 ast_config_destroy(msg_cfg);
09389 return 9;
09390 }
09391 } else {
09392 res = '2';
09393 }
09394 break;
09395
09396 case '2':
09397
09398 if (!ast_strlen_zero(vmu->dialout)) {
09399 res = dialout(chan, vmu, NULL, vmu->dialout);
09400 if (res) {
09401 ast_config_destroy(msg_cfg);
09402 return 9;
09403 }
09404 } else {
09405 if (option_verbose > 2)
09406 ast_verbose( VERBOSE_PREFIX_3 "Caller can not specify callback number - no dialout context available\n");
09407 res = ast_play_and_wait(chan, "vm-sorry");
09408 }
09409 ast_config_destroy(msg_cfg);
09410 return res;
09411 case '*':
09412 res = 't';
09413 break;
09414 case '3':
09415 case '4':
09416 case '5':
09417 case '6':
09418 case '7':
09419 case '8':
09420 case '9':
09421 case '0':
09422
09423 res = ast_play_and_wait(chan, "vm-sorry");
09424 retries++;
09425 break;
09426 default:
09427 if (num) {
09428 if (option_verbose > 2)
09429 ast_verbose( VERBOSE_PREFIX_3 "Confirm CID number '%s' is number to use for callback\n", num);
09430 res = ast_play_and_wait(chan, "vm-num-i-have");
09431 if (!res)
09432 res = play_message_callerid(chan, vms, num, vmu->context, 1);
09433 if (!res)
09434 res = ast_play_and_wait(chan, "vm-tocallnum");
09435
09436 if (!ast_strlen_zero(vmu->dialout)) {
09437 if (!res)
09438 res = ast_play_and_wait(chan, "vm-calldiffnum");
09439 }
09440 } else {
09441 res = ast_play_and_wait(chan, "vm-nonumber");
09442 if (!ast_strlen_zero(vmu->dialout)) {
09443 if (!res)
09444 res = ast_play_and_wait(chan, "vm-toenternumber");
09445 }
09446 }
09447 if (!res)
09448 res = ast_play_and_wait(chan, "vm-star-cancel");
09449 if (!res)
09450 res = ast_waitfordigit(chan, 6000);
09451 if (!res) {
09452 retries++;
09453 if (retries > 3)
09454 res = 't';
09455 }
09456 break;
09457
09458 }
09459 if (res == 't')
09460 res = 0;
09461 else if (res == '*')
09462 res = -1;
09463 }
09464 break;
09465
09466 case 1:
09467
09468 if (ast_strlen_zero(cid))
09469 break;
09470
09471 ast_callerid_parse(cid, &name, &num);
09472 if (!num) {
09473 if (option_verbose > 2)
09474 ast_verbose(VERBOSE_PREFIX_3 "No CID number available, no reply sent\n");
09475 if (!res)
09476 res = ast_play_and_wait(chan, "vm-nonumber");
09477 ast_config_destroy(msg_cfg);
09478 return res;
09479 } else {
09480 struct ast_vm_user vmu2;
09481 if (find_user(&vmu2, vmu->context, num)) {
09482 struct leave_vm_options leave_options;
09483 char mailbox[AST_MAX_EXTENSION * 2 + 2];
09484 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
09485
09486 if (option_verbose > 2)
09487 ast_verbose(VERBOSE_PREFIX_3 "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
09488
09489 memset(&leave_options, 0, sizeof(leave_options));
09490 leave_options.record_gain = record_gain;
09491 res = leave_voicemail(chan, mailbox, &leave_options);
09492 if (!res)
09493 res = 't';
09494 ast_config_destroy(msg_cfg);
09495 return res;
09496 } else {
09497
09498 if (option_verbose > 2)
09499 ast_verbose( VERBOSE_PREFIX_3 "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
09500 ast_play_and_wait(chan, "vm-nobox");
09501 res = 't';
09502 ast_config_destroy(msg_cfg);
09503 return res;
09504 }
09505 }
09506 res = 0;
09507
09508 break;
09509 }
09510
09511 #ifndef IMAP_STORAGE
09512 ast_config_destroy(msg_cfg);
09513
09514 if (!res) {
09515 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
09516 vms->heard[msg] = 1;
09517 res = wait_file(chan, vms, vms->fn);
09518 }
09519 #endif
09520 return res;
09521 }
09522
09523 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
09524 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
09525 signed char record_gain, struct vm_state *vms)
09526 {
09527
09528 int res = 0;
09529 int cmd = 0;
09530 int max_attempts = 3;
09531 int attempts = 0;
09532 int recorded = 0;
09533 int message_exists = 0;
09534 signed char zero_gain = 0;
09535 char tempfile[PATH_MAX];
09536 char *acceptdtmf = "#";
09537 char *canceldtmf = "";
09538 int canceleddtmf = 0;
09539
09540
09541
09542
09543 if (duration == NULL) {
09544 ast_log(LOG_WARNING, "Error play_record_review called without duration pointer\n");
09545 return -1;
09546 }
09547
09548 if (!outsidecaller)
09549 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
09550 else
09551 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
09552
09553 cmd = '3';
09554
09555 while ((cmd >= 0) && (cmd != 't')) {
09556 switch (cmd) {
09557 case '1':
09558 if (!message_exists) {
09559
09560 cmd = '3';
09561 break;
09562 } else {
09563
09564 if (option_verbose > 2)
09565 ast_verbose(VERBOSE_PREFIX_3 "Saving message as is\n");
09566 if (!outsidecaller)
09567 ast_filerename(tempfile, recordfile, NULL);
09568 ast_stream_and_wait(chan, "vm-msgsaved", chan->language, "");
09569 if (!outsidecaller) {
09570 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms);
09571 DISPOSE(recordfile, -1);
09572 }
09573 cmd = 't';
09574 return res;
09575 }
09576 case '2':
09577
09578 if (option_verbose > 2)
09579 ast_verbose(VERBOSE_PREFIX_3 "Reviewing the message\n");
09580 cmd = ast_stream_and_wait(chan, tempfile, chan->language, AST_DIGIT_ANY);
09581 break;
09582 case '3':
09583 message_exists = 0;
09584
09585 if (recorded == 1) {
09586 if (option_verbose > 2)
09587 ast_verbose(VERBOSE_PREFIX_3 "Re-recording the message\n");
09588 } else {
09589 if (option_verbose > 2)
09590 ast_verbose(VERBOSE_PREFIX_3 "Recording the message\n");
09591 }
09592 if (recorded && outsidecaller) {
09593 cmd = ast_play_and_wait(chan, INTRO);
09594 cmd = ast_play_and_wait(chan, "beep");
09595 }
09596 recorded = 1;
09597
09598 if (record_gain)
09599 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
09600 if (ast_test_flag(vmu, VM_OPERATOR))
09601 canceldtmf = "0";
09602 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
09603 if (strchr(canceldtmf, cmd)) {
09604
09605 canceleddtmf = 1;
09606 }
09607 if (record_gain)
09608 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
09609 if (cmd == -1) {
09610
09611 if (!outsidecaller) {
09612
09613 ast_filedelete(tempfile, NULL);
09614 }
09615 return cmd;
09616 }
09617 if (cmd == '0') {
09618 break;
09619 } else if (cmd == '*') {
09620 break;
09621 }
09622 #if 0
09623 else if (vmu->review && (*duration < 5)) {
09624
09625 if (option_verbose > 2)
09626 ast_verbose(VERBOSE_PREFIX_3 "Message too short\n");
09627 cmd = ast_play_and_wait(chan, "vm-tooshort");
09628 cmd = ast_filedelete(tempfile, NULL);
09629 break;
09630 }
09631 else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
09632
09633 if (option_verbose > 2)
09634 ast_verbose(VERBOSE_PREFIX_3 "Nothing recorded\n");
09635 cmd = ast_filedelete(tempfile, NULL);
09636 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
09637 if (!cmd)
09638 cmd = ast_play_and_wait(chan, "vm-speakup");
09639 break;
09640 }
09641 #endif
09642 else {
09643
09644 message_exists = 1;
09645 cmd = 0;
09646 }
09647 break;
09648 case '4':
09649 case '5':
09650 case '6':
09651 case '7':
09652 case '8':
09653 case '9':
09654 case '*':
09655 case '#':
09656 cmd = ast_play_and_wait(chan, "vm-sorry");
09657 break;
09658 #if 0
09659
09660
09661 case '*':
09662
09663 cmd = ast_play_and_wait(chan, "vm-deleted");
09664 cmd = ast_filedelete(tempfile, NULL);
09665 if (outsidecaller) {
09666 res = vm_exec(chan, NULL);
09667 return res;
09668 }
09669 else
09670 return 1;
09671 #endif
09672 case '0':
09673 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
09674 cmd = ast_play_and_wait(chan, "vm-sorry");
09675 break;
09676 }
09677 if (message_exists || recorded) {
09678 cmd = ast_play_and_wait(chan, "vm-saveoper");
09679 if (!cmd)
09680 cmd = ast_waitfordigit(chan, 3000);
09681 if (cmd == '1') {
09682 ast_filerename(tempfile, recordfile, NULL);
09683 ast_play_and_wait(chan, "vm-msgsaved");
09684 cmd = '0';
09685 } else {
09686 ast_play_and_wait(chan, "vm-deleted");
09687 DELETE(tempfile, -1, tempfile, vmu);
09688 cmd = '0';
09689 }
09690 }
09691 return cmd;
09692 default:
09693
09694
09695
09696 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
09697 return cmd;
09698 if (message_exists) {
09699 cmd = ast_play_and_wait(chan, "vm-review");
09700 } else {
09701 cmd = ast_play_and_wait(chan, "vm-torerecord");
09702 if (!cmd)
09703 cmd = ast_waitfordigit(chan, 600);
09704 }
09705
09706 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
09707 cmd = ast_play_and_wait(chan, "vm-reachoper");
09708 if (!cmd)
09709 cmd = ast_waitfordigit(chan, 600);
09710 }
09711 #if 0
09712 if (!cmd)
09713 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
09714 #endif
09715 if (!cmd)
09716 cmd = ast_waitfordigit(chan, 6000);
09717 if (!cmd) {
09718 attempts++;
09719 }
09720 if (attempts > max_attempts) {
09721 cmd = 't';
09722 }
09723 }
09724 }
09725 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
09726
09727 ast_filedelete(tempfile, NULL);
09728 }
09729
09730 if (cmd != 't' && outsidecaller)
09731 ast_play_and_wait(chan, "vm-goodbye");
09732
09733 return cmd;
09734 }
09735
09736
09737
09738
09739
09740 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
09741 .load = load_module,
09742 .unload = unload_module,
09743 .reload = reload,
09744 );