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