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