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