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