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