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