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
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 #include "asterisk.h"
00072
00073 #ifdef IMAP_STORAGE
00074 #include <ctype.h>
00075 #include <signal.h>
00076 #include <pwd.h>
00077 #ifdef USE_SYSTEM_IMAP
00078 #include <imap/c-client.h>
00079 #include <imap/imap4r1.h>
00080 #include <imap/linkage.h>
00081 #elif defined (USE_SYSTEM_CCLIENT)
00082 #include <c-client/c-client.h>
00083 #include <c-client/imap4r1.h>
00084 #include <c-client/linkage.h>
00085 #else
00086 #include "c-client.h"
00087 #include "imap4r1.h"
00088 #include "linkage.h"
00089 #endif
00090 #endif
00091
00092 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 250976 $")
00093
00094 #include "asterisk/paths.h"
00095 #include <sys/time.h>
00096 #include <sys/stat.h>
00097 #include <sys/mman.h>
00098 #include <time.h>
00099 #include <dirent.h>
00100
00101 #include "asterisk/logger.h"
00102 #include "asterisk/lock.h"
00103 #include "asterisk/file.h"
00104 #include "asterisk/channel.h"
00105 #include "asterisk/pbx.h"
00106 #include "asterisk/config.h"
00107 #include "asterisk/say.h"
00108 #include "asterisk/module.h"
00109 #include "asterisk/adsi.h"
00110 #include "asterisk/app.h"
00111 #include "asterisk/manager.h"
00112 #include "asterisk/dsp.h"
00113 #include "asterisk/localtime.h"
00114 #include "asterisk/cli.h"
00115 #include "asterisk/utils.h"
00116 #include "asterisk/stringfields.h"
00117 #include "asterisk/smdi.h"
00118 #include "asterisk/astobj2.h"
00119 #include "asterisk/event.h"
00120 #include "asterisk/taskprocessor.h"
00121
00122 #ifdef ODBC_STORAGE
00123 #include "asterisk/res_odbc.h"
00124 #endif
00125
00126 #ifdef IMAP_STORAGE
00127 #include "asterisk/threadstorage.h"
00128
00129 static char imapserver[48];
00130 static char imapport[8];
00131 static char imapflags[128];
00132 static char imapfolder[64];
00133 static char imapparentfolder[64] = "\0";
00134 static char greetingfolder[64];
00135 static char authuser[32];
00136 static char authpassword[42];
00137 static int imapversion = 1;
00138
00139 static int expungeonhangup = 1;
00140 static int imapgreetings = 0;
00141 static char delimiter = '\0';
00142
00143 struct vm_state;
00144 struct ast_vm_user;
00145
00146 AST_THREADSTORAGE(ts_vmstate);
00147
00148
00149 static int init_mailstream(struct vm_state *vms, int box);
00150 static void write_file(char *filename, char *buffer, unsigned long len);
00151 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00152 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00153 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00154 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00155 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00156 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00157 static void vmstate_insert(struct vm_state *vms);
00158 static void vmstate_delete(struct vm_state *vms);
00159 static void set_update(MAILSTREAM * stream);
00160 static void init_vm_state(struct vm_state *vms);
00161 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00162 static void get_mailbox_delimiter(MAILSTREAM *stream);
00163 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00164 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00165 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag);
00166 static void update_messages_by_imapuser(const char *user, unsigned long number);
00167 static int vm_delete(char *file);
00168
00169 static int imap_remove_file (char *dir, int msgnum);
00170 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00171 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00172 static void check_quota(struct vm_state *vms, char *mailbox);
00173 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00174 struct vmstate {
00175 struct vm_state *vms;
00176 AST_LIST_ENTRY(vmstate) list;
00177 };
00178
00179 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00180
00181 #endif
00182
00183 #define SMDI_MWI_WAIT_TIMEOUT 1000
00184
00185 #define COMMAND_TIMEOUT 5000
00186
00187 #define VOICEMAIL_DIR_MODE 0777
00188 #define VOICEMAIL_FILE_MODE 0666
00189 #define CHUNKSIZE 65536
00190
00191 #define VOICEMAIL_CONFIG "voicemail.conf"
00192 #define ASTERISK_USERNAME "asterisk"
00193
00194
00195
00196
00197 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00198 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00199 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00200 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00201 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00202 #define VALID_DTMF "1234567890*#"
00203
00204
00205
00206 #define SENDMAIL "/usr/sbin/sendmail -t"
00207
00208 #define INTRO "vm-intro"
00209
00210 #define MAXMSG 100
00211 #define MAXMSGLIMIT 9999
00212
00213 #define MINPASSWORD 0
00214
00215 #define BASELINELEN 72
00216 #define BASEMAXINLINE 256
00217 #define eol "\r\n"
00218
00219 #define MAX_DATETIME_FORMAT 512
00220 #define MAX_NUM_CID_CONTEXTS 10
00221
00222 #define VM_REVIEW (1 << 0)
00223 #define VM_OPERATOR (1 << 1)
00224 #define VM_SAYCID (1 << 2)
00225 #define VM_SVMAIL (1 << 3)
00226 #define VM_ENVELOPE (1 << 4)
00227 #define VM_SAYDURATION (1 << 5)
00228 #define VM_SKIPAFTERCMD (1 << 6)
00229 #define VM_FORCENAME (1 << 7)
00230 #define VM_FORCEGREET (1 << 8)
00231 #define VM_PBXSKIP (1 << 9)
00232 #define VM_DIRECFORWARD (1 << 10)
00233 #define VM_ATTACH (1 << 11)
00234 #define VM_DELETE (1 << 12)
00235 #define VM_ALLOCED (1 << 13)
00236 #define VM_SEARCH (1 << 14)
00237 #define VM_TEMPGREETWARN (1 << 15)
00238 #define VM_MOVEHEARD (1 << 16)
00239 #define VM_MESSAGEWRAP (1 << 17)
00240 #define VM_FWDURGAUTO (1 << 18)
00241 #define ERROR_LOCK_PATH -100
00242
00243
00244 enum {
00245 NEW_FOLDER,
00246 OLD_FOLDER,
00247 WORK_FOLDER,
00248 FAMILY_FOLDER,
00249 FRIENDS_FOLDER,
00250 GREETINGS_FOLDER
00251 } vm_box;
00252
00253 enum {
00254 OPT_SILENT = (1 << 0),
00255 OPT_BUSY_GREETING = (1 << 1),
00256 OPT_UNAVAIL_GREETING = (1 << 2),
00257 OPT_RECORDGAIN = (1 << 3),
00258 OPT_PREPEND_MAILBOX = (1 << 4),
00259 OPT_AUTOPLAY = (1 << 6),
00260 OPT_DTMFEXIT = (1 << 7),
00261 OPT_MESSAGE_Urgent = (1 << 8),
00262 OPT_MESSAGE_PRIORITY = (1 << 9)
00263 } vm_option_flags;
00264
00265 enum {
00266 OPT_ARG_RECORDGAIN = 0,
00267 OPT_ARG_PLAYFOLDER = 1,
00268 OPT_ARG_DTMFEXIT = 2,
00269
00270 OPT_ARG_ARRAY_SIZE = 3,
00271 } vm_option_args;
00272
00273 AST_APP_OPTIONS(vm_app_options, {
00274 AST_APP_OPTION('s', OPT_SILENT),
00275 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00276 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00277 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00278 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00279 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00280 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00281 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00282 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00283 });
00284
00285 static int load_config(int reload);
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 struct baseio {
00371 int iocp;
00372 int iolen;
00373 int linelength;
00374 int ateof;
00375 unsigned char iobuf[BASEMAXINLINE];
00376 };
00377
00378
00379
00380 struct ast_vm_user {
00381 char context[AST_MAX_CONTEXT];
00382 char mailbox[AST_MAX_EXTENSION];
00383 char password[80];
00384 char fullname[80];
00385 char email[80];
00386 char pager[80];
00387 char serveremail[80];
00388 char mailcmd[160];
00389 char language[MAX_LANGUAGE];
00390 char zonetag[80];
00391 char callback[80];
00392 char dialout[80];
00393 char uniqueid[80];
00394 char exit[80];
00395 char attachfmt[20];
00396 unsigned int flags;
00397 int saydurationm;
00398 int maxmsg;
00399 int maxdeletedmsg;
00400 int maxsecs;
00401 #ifdef IMAP_STORAGE
00402 char imapuser[80];
00403 char imappassword[80];
00404 char imapvmshareid[80];
00405 int imapversion;
00406 #endif
00407 double volgain;
00408 AST_LIST_ENTRY(ast_vm_user) list;
00409 };
00410
00411
00412 struct vm_zone {
00413 AST_LIST_ENTRY(vm_zone) list;
00414 char name[80];
00415 char timezone[80];
00416 char msg_format[512];
00417 };
00418
00419 #define VMSTATE_MAX_MSG_ARRAY 256
00420
00421
00422 struct vm_state {
00423 char curbox[80];
00424 char username[80];
00425 char context[80];
00426 char curdir[PATH_MAX];
00427 char vmbox[PATH_MAX];
00428 char fn[PATH_MAX];
00429 char intro[PATH_MAX];
00430 int *deleted;
00431 int *heard;
00432 int curmsg;
00433 int lastmsg;
00434 int newmessages;
00435 int oldmessages;
00436 int urgentmessages;
00437 int starting;
00438 int repeats;
00439 #ifdef IMAP_STORAGE
00440 ast_mutex_t lock;
00441 int updated;
00442 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00443 MAILSTREAM *mailstream;
00444 int vmArrayIndex;
00445 char imapuser[80];
00446 int imapversion;
00447 int interactive;
00448 char introfn[PATH_MAX];
00449 unsigned int quota_limit;
00450 unsigned int quota_usage;
00451 struct vm_state *persist_vms;
00452 #endif
00453 };
00454
00455 #ifdef ODBC_STORAGE
00456 static char odbc_database[80];
00457 static char odbc_table[80];
00458 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00459 #define DISPOSE(a,b) remove_file(a,b)
00460 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00461 #define EXISTS(a,b,c,d) (message_exists(a,b))
00462 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00463 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00464 #define DELETE(a,b,c,d) (delete_file(a,b))
00465 #else
00466 #ifdef IMAP_STORAGE
00467 #define DISPOSE(a,b) (imap_remove_file(a,b))
00468 #define STORE(a,b,c,d,e,f,g,h,i,j) (imap_store_file(a,b,c,d,e,f,g,h,i,j))
00469 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00470 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00471 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00472 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00473 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00474 #else
00475 #define RETRIEVE(a,b,c,d)
00476 #define DISPOSE(a,b)
00477 #define STORE(a,b,c,d,e,f,g,h,i,j)
00478 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00479 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00480 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00481 #define DELETE(a,b,c,d) (vm_delete(c))
00482 #endif
00483 #endif
00484
00485 static char VM_SPOOL_DIR[PATH_MAX];
00486
00487 static char ext_pass_cmd[128];
00488 static char ext_pass_check_cmd[128];
00489
00490 static int my_umask;
00491
00492 #define PWDCHANGE_INTERNAL (1 << 1)
00493 #define PWDCHANGE_EXTERNAL (1 << 2)
00494 static int pwdchange = PWDCHANGE_INTERNAL;
00495
00496 #ifdef ODBC_STORAGE
00497 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00498 #else
00499 # ifdef IMAP_STORAGE
00500 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00501 # else
00502 # define tdesc "Comedian Mail (Voicemail System)"
00503 # endif
00504 #endif
00505
00506 static char userscontext[AST_MAX_EXTENSION] = "default";
00507
00508 static char *addesc = "Comedian Mail";
00509
00510 static char *synopsis_vm = "Leave a Voicemail message";
00511
00512 static char *descrip_vm =
00513 " VoiceMail(mailbox[@context][&mailbox[@context]][...][,options]): This\n"
00514 "application allows the calling party to leave a message for the specified\n"
00515 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
00516 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
00517 "specified mailbox does not exist.\n"
00518 " The Voicemail application will exit if any of the following DTMF digits are\n"
00519 "received:\n"
00520 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
00521 " * - Jump to the 'a' extension in the current dialplan context.\n"
00522 " This application will set the following channel variable upon completion:\n"
00523 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
00524 " application. The possible values are:\n"
00525 " SUCCESS | USEREXIT | FAILED\n\n"
00526 " Options:\n"
00527 " b - Play the 'busy' greeting to the calling party.\n"
00528 " d([c]) - Accept digits for a new extension in context c, if played during\n"
00529 " the greeting. Context defaults to the current context.\n"
00530 " g(#) - Use the specified amount of gain when recording the voicemail\n"
00531 " message. The units are whole-number decibels (dB).\n"
00532 " Only works on supported technologies, which is DAHDI only.\n"
00533 " s - Skip the playback of instructions for leaving a message to the\n"
00534 " calling party.\n"
00535 " u - Play the 'unavailable' greeting.\n"
00536 " U - Mark message as Urgent.\n"
00537 " P - Mark message as PRIORITY.\n";
00538
00539 static char *synopsis_vmain = "Check Voicemail messages";
00540
00541 static char *descrip_vmain =
00542 " VoiceMailMain([mailbox][@context][,options]): This application allows the\n"
00543 "calling party to check voicemail messages. A specific mailbox, and optional\n"
00544 "corresponding context, may be specified. If a mailbox is not provided, the\n"
00545 "calling party will be prompted to enter one. If a context is not specified,\n"
00546 "the 'default' context will be used.\n\n"
00547 " Options:\n"
00548 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
00549 " is entered by the caller.\n"
00550 " g(#) - Use the specified amount of gain when recording a voicemail\n"
00551 " message. The units are whole-number decibels (dB).\n"
00552 " s - Skip checking the passcode for the mailbox.\n"
00553 " a(#) - Skip folder prompt and go directly to folder specified.\n"
00554 " Accepted values are:\n"
00555 " 0 for INBOX\n"
00556 " 1 for Old\n"
00557 " 2 for Work\n"
00558 " 3 for Family\n"
00559 " 4 for Friends\n"
00560 " 5 for Cust1\n"
00561 " 6 for Cust2\n"
00562 " 7 for Cust3\n"
00563 " 8 for Cust4\n"
00564 " 9 for Cust5\n"
00565 " Defaults to 0 (INBOX).\n";
00566
00567 static char *synopsis_vm_box_exists =
00568 "Check to see if Voicemail mailbox exists";
00569
00570 static char *descrip_vm_box_exists =
00571 " MailboxExists(mailbox[@context][,options]): Check to see if the specified\n"
00572 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
00573 "will be used.\n"
00574 " This application will set the following channel variable upon completion:\n"
00575 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
00576 " MailboxExists application. Possible values include:\n"
00577 " SUCCESS | FAILED\n\n"
00578 " Options: (none)\n";
00579
00580 static char *synopsis_vmauthenticate = "Authenticate with Voicemail passwords";
00581
00582 static char *descrip_vmauthenticate =
00583 " VMAuthenticate([mailbox][@context][,options]): This application behaves the\n"
00584 "same way as the Authenticate application, but the passwords are taken from\n"
00585 "voicemail.conf.\n"
00586 " If the mailbox is specified, only that mailbox's password will be considered\n"
00587 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
00588 "be set with the authenticated mailbox.\n\n"
00589 " Options:\n"
00590 " s - Skip playing the initial prompts.\n";
00591
00592
00593 static char *app = "VoiceMail";
00594
00595
00596 static char *app2 = "VoiceMailMain";
00597
00598 static char *app3 = "MailboxExists";
00599 static char *app4 = "VMAuthenticate";
00600
00601 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00602 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00603 static char zonetag[80];
00604 static int maxsilence;
00605 static int maxmsg;
00606 static int maxdeletedmsg;
00607 static int silencethreshold = 128;
00608 static char serveremail[80];
00609 static char mailcmd[160];
00610 static char externnotify[160];
00611 static struct ast_smdi_interface *smdi_iface = NULL;
00612 static char vmfmts[80];
00613 static double volgain;
00614 static int vmminsecs;
00615 static int vmmaxsecs;
00616 static int maxgreet;
00617 static int skipms;
00618 static int maxlogins;
00619 static int minpassword;
00620
00621
00622
00623 static unsigned int poll_mailboxes;
00624
00625
00626 static unsigned int poll_freq;
00627
00628 #define DEFAULT_POLL_FREQ 30
00629
00630 AST_MUTEX_DEFINE_STATIC(poll_lock);
00631 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00632 static pthread_t poll_thread = AST_PTHREADT_NULL;
00633 static unsigned char poll_thread_run;
00634
00635
00636 static struct ast_event_sub *mwi_sub_sub;
00637
00638 static struct ast_event_sub *mwi_unsub_sub;
00639
00640
00641
00642
00643
00644
00645
00646
00647 struct mwi_sub {
00648 AST_RWLIST_ENTRY(mwi_sub) entry;
00649 int old_urgent;
00650 int old_new;
00651 int old_old;
00652 uint32_t uniqueid;
00653 char mailbox[1];
00654 };
00655
00656 struct mwi_sub_task {
00657 const char *mailbox;
00658 const char *context;
00659 uint32_t uniqueid;
00660 };
00661
00662 static struct ast_taskprocessor *mwi_subscription_tps;
00663
00664 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00665
00666
00667 static char listen_control_forward_key[12];
00668 static char listen_control_reverse_key[12];
00669 static char listen_control_pause_key[12];
00670 static char listen_control_restart_key[12];
00671 static char listen_control_stop_key[12];
00672
00673
00674 static char vm_password[80] = "vm-password";
00675 static char vm_newpassword[80] = "vm-newpassword";
00676 static char vm_passchanged[80] = "vm-passchanged";
00677 static char vm_reenterpassword[80] = "vm-reenterpassword";
00678 static char vm_mismatch[80] = "vm-mismatch";
00679 static char vm_invalid_password[80] = "vm-invalid-password";
00680 static char vm_pls_try_again[80] = "vm-pls-try-again";
00681
00682 static struct ast_flags globalflags = {0};
00683
00684 static int saydurationminfo;
00685
00686 static char dialcontext[AST_MAX_CONTEXT] = "";
00687 static char callcontext[AST_MAX_CONTEXT] = "";
00688 static char exitcontext[AST_MAX_CONTEXT] = "";
00689
00690 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00691
00692
00693 static char *emailbody = NULL;
00694 static char *emailsubject = NULL;
00695 static char *pagerbody = NULL;
00696 static char *pagersubject = NULL;
00697 static char fromstring[100];
00698 static char pagerfromstring[100];
00699 static char charset[32] = "ISO-8859-1";
00700
00701 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00702 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00703 static int adsiver = 1;
00704 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00705
00706
00707 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00708 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);
00709 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00710 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00711 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00712 signed char record_gain, struct vm_state *vms, char *flag);
00713 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00714 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00715 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag);
00716 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag);
00717 static void apply_options(struct ast_vm_user *vmu, const char *options);
00718 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum);
00719 static int is_valid_dtmf(const char *key);
00720
00721 struct ao2_container *inprocess_container;
00722
00723 struct inprocess {
00724 int count;
00725 char *context;
00726 char mailbox[0];
00727 };
00728
00729 static int inprocess_hash_fn(const void *obj, const int flags)
00730 {
00731 const struct inprocess *i = obj;
00732 return atoi(i->mailbox);
00733 }
00734
00735 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00736 {
00737 struct inprocess *i = obj, *j = arg;
00738 if (!strcmp(i->mailbox, j->mailbox)) {
00739 return 0;
00740 }
00741 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00742 }
00743
00744 static int inprocess_count(const char *context, const char *mailbox, int delta)
00745 {
00746 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00747 arg->context = arg->mailbox + strlen(mailbox) + 1;
00748 strcpy(arg->mailbox, mailbox);
00749 strcpy(arg->context, context);
00750 ao2_lock(inprocess_container);
00751 if ((i = ao2_find(inprocess_container, arg, 0))) {
00752 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00753 ao2_unlock(inprocess_container);
00754 ao2_ref(i, -1);
00755 return ret;
00756 }
00757 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00758 ao2_unlock(inprocess_container);
00759 return 0;
00760 }
00761 i->context = i->mailbox + strlen(mailbox) + 1;
00762 strcpy(i->mailbox, mailbox);
00763 strcpy(i->context, context);
00764 i->count = delta;
00765 ao2_link(inprocess_container, i);
00766 ao2_unlock(inprocess_container);
00767 ao2_ref(i, -1);
00768 return 0;
00769 }
00770
00771 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00772 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00773 #endif
00774
00775
00776
00777
00778
00779
00780
00781 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00782 {
00783 char *bufptr = buf;
00784 for (; *input; input++) {
00785 if (*input < 32) {
00786 continue;
00787 }
00788 *bufptr++ = *input;
00789 if (bufptr == buf + buflen - 1) {
00790 break;
00791 }
00792 }
00793 *bufptr = '\0';
00794 return buf;
00795 }
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810 static void populate_defaults(struct ast_vm_user *vmu)
00811 {
00812 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00813 if (saydurationminfo)
00814 vmu->saydurationm = saydurationminfo;
00815 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
00816 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
00817 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
00818 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
00819 if (vmmaxsecs)
00820 vmu->maxsecs = vmmaxsecs;
00821 if (maxmsg)
00822 vmu->maxmsg = maxmsg;
00823 if (maxdeletedmsg)
00824 vmu->maxdeletedmsg = maxdeletedmsg;
00825 vmu->volgain = volgain;
00826 }
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
00837 {
00838 int x;
00839 if (!strcasecmp(var, "attach")) {
00840 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
00841 } else if (!strcasecmp(var, "attachfmt")) {
00842 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
00843 } else if (!strcasecmp(var, "serveremail")) {
00844 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
00845 } else if (!strcasecmp(var, "language")) {
00846 ast_copy_string(vmu->language, value, sizeof(vmu->language));
00847 } else if (!strcasecmp(var, "tz")) {
00848 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
00849 #ifdef IMAP_STORAGE
00850 } else if (!strcasecmp(var, "imapuser")) {
00851 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
00852 vmu->imapversion = imapversion;
00853 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
00854 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
00855 vmu->imapversion = imapversion;
00856 } else if (!strcasecmp(var, "imapvmshareid")) {
00857 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
00858 vmu->imapversion = imapversion;
00859 #endif
00860 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
00861 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
00862 } else if (!strcasecmp(var, "saycid")){
00863 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
00864 } else if (!strcasecmp(var,"sendvoicemail")){
00865 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
00866 } else if (!strcasecmp(var, "review")){
00867 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
00868 } else if (!strcasecmp(var, "tempgreetwarn")){
00869 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
00870 } else if (!strcasecmp(var, "messagewrap")){
00871 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
00872 } else if (!strcasecmp(var, "operator")) {
00873 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
00874 } else if (!strcasecmp(var, "envelope")){
00875 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
00876 } else if (!strcasecmp(var, "moveheard")){
00877 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
00878 } else if (!strcasecmp(var, "sayduration")){
00879 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
00880 } else if (!strcasecmp(var, "saydurationm")){
00881 if (sscanf(value, "%30d", &x) == 1) {
00882 vmu->saydurationm = x;
00883 } else {
00884 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
00885 }
00886 } else if (!strcasecmp(var, "forcename")){
00887 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
00888 } else if (!strcasecmp(var, "forcegreetings")){
00889 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
00890 } else if (!strcasecmp(var, "callback")) {
00891 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
00892 } else if (!strcasecmp(var, "dialout")) {
00893 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
00894 } else if (!strcasecmp(var, "exitcontext")) {
00895 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
00896 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
00897 vmu->maxsecs = atoi(value);
00898 if (vmu->maxsecs <= 0) {
00899 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
00900 vmu->maxsecs = vmmaxsecs;
00901 } else {
00902 vmu->maxsecs = atoi(value);
00903 }
00904 if (!strcasecmp(var, "maxmessage"))
00905 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
00906 } else if (!strcasecmp(var, "maxmsg")) {
00907 vmu->maxmsg = atoi(value);
00908 if (vmu->maxmsg <= 0) {
00909 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
00910 vmu->maxmsg = MAXMSG;
00911 } else if (vmu->maxmsg > MAXMSGLIMIT) {
00912 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
00913 vmu->maxmsg = MAXMSGLIMIT;
00914 }
00915 } else if (!strcasecmp(var, "backupdeleted")) {
00916 if (sscanf(value, "%30d", &x) == 1)
00917 vmu->maxdeletedmsg = x;
00918 else if (ast_true(value))
00919 vmu->maxdeletedmsg = MAXMSG;
00920 else
00921 vmu->maxdeletedmsg = 0;
00922
00923 if (vmu->maxdeletedmsg < 0) {
00924 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
00925 vmu->maxdeletedmsg = MAXMSG;
00926 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
00927 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
00928 vmu->maxdeletedmsg = MAXMSGLIMIT;
00929 }
00930 } else if (!strcasecmp(var, "volgain")) {
00931 sscanf(value, "%30lf", &vmu->volgain);
00932 } else if (!strcasecmp(var, "options")) {
00933 apply_options(vmu, value);
00934 }
00935 }
00936
00937 static char *vm_check_password_shell(char *command, char *buf, size_t len)
00938 {
00939 int fds[2], pid = 0;
00940
00941 memset(buf, 0, len);
00942
00943 if (pipe(fds)) {
00944 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
00945 } else {
00946
00947 pid = ast_safe_fork(0);
00948
00949 if (pid < 0) {
00950
00951 close(fds[0]);
00952 close(fds[1]);
00953 snprintf(buf, len, "FAILURE: Fork failed");
00954 } else if (pid) {
00955
00956 close(fds[1]);
00957 if (read(fds[0], buf, len) < 0) {
00958 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
00959 }
00960 close(fds[0]);
00961 } else {
00962
00963 AST_DECLARE_APP_ARGS(arg,
00964 AST_APP_ARG(v)[20];
00965 );
00966 char *mycmd = ast_strdupa(command);
00967
00968 close(fds[0]);
00969 dup2(fds[1], STDOUT_FILENO);
00970 close(fds[1]);
00971 ast_close_fds_above_n(STDOUT_FILENO);
00972
00973 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
00974
00975 execv(arg.v[0], arg.v);
00976 printf("FAILURE: %s", strerror(errno));
00977 _exit(0);
00978 }
00979 }
00980 return buf;
00981 }
00982
00983
00984
00985
00986
00987
00988
00989
00990 static int check_password(struct ast_vm_user *vmu, char *password)
00991 {
00992
00993 if (strlen(password) < minpassword)
00994 return 1;
00995 if (!ast_strlen_zero(ext_pass_check_cmd)) {
00996 char cmd[255], buf[255];
00997
00998 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
00999
01000 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01001 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01002 ast_debug(5, "Result: %s\n", buf);
01003 if (!strncasecmp(buf, "VALID", 5)) {
01004 ast_debug(3, "Passed password check: '%s'\n", buf);
01005 return 0;
01006 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01007 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01008 return 0;
01009 } else {
01010 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01011 return 1;
01012 }
01013 }
01014 }
01015 return 0;
01016 }
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01029 {
01030 int res = -1;
01031 if (!strcmp(vmu->password, password)) {
01032
01033 res = 0;
01034 } else if (!ast_strlen_zero(vmu->uniqueid)) {
01035 if (strlen(password) > 10) {
01036 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01037 }
01038 if (ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, SENTINEL) > 0) {
01039 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01040 res = 0;
01041 }
01042 }
01043 return res;
01044 }
01045
01046
01047
01048
01049 static void apply_options(struct ast_vm_user *vmu, const char *options)
01050 {
01051 char *stringp;
01052 char *s;
01053 char *var, *value;
01054 stringp = ast_strdupa(options);
01055 while ((s = strsep(&stringp, "|"))) {
01056 value = s;
01057 if ((var = strsep(&value, "=")) && value) {
01058 apply_option(vmu, var, value);
01059 }
01060 }
01061 }
01062
01063
01064
01065
01066
01067
01068 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01069 {
01070 struct ast_variable *tmp;
01071 tmp = var;
01072 while (tmp) {
01073 if (!strcasecmp(tmp->name, "vmsecret")) {
01074 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
01075 } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) {
01076 if (ast_strlen_zero(retval->password))
01077 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
01078 } else if (!strcasecmp(tmp->name, "uniqueid")) {
01079 ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
01080 } else if (!strcasecmp(tmp->name, "pager")) {
01081 ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
01082 } else if (!strcasecmp(tmp->name, "email")) {
01083 ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
01084 } else if (!strcasecmp(tmp->name, "fullname")) {
01085 ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
01086 } else if (!strcasecmp(tmp->name, "context")) {
01087 ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
01088 #ifdef IMAP_STORAGE
01089 } else if (!strcasecmp(tmp->name, "imapuser")) {
01090 ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
01091 retval->imapversion = imapversion;
01092 } else if (!strcasecmp(tmp->name, "imappassword") || !strcasecmp(tmp->name, "imapsecret")) {
01093 ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
01094 retval->imapversion = imapversion;
01095 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01096 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01097 retval->imapversion = imapversion;
01098 #endif
01099 } else
01100 apply_option(retval, tmp->name, tmp->value);
01101 tmp = tmp->next;
01102 }
01103 }
01104
01105
01106
01107
01108
01109
01110
01111
01112 static int is_valid_dtmf(const char *key)
01113 {
01114 int i;
01115 char *local_key = ast_strdupa(key);
01116
01117 for (i = 0; i < strlen(key); ++i) {
01118 if (!strchr(VALID_DTMF, *local_key)) {
01119 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01120 return 0;
01121 }
01122 local_key++;
01123 }
01124 return 1;
01125 }
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01138 {
01139 struct ast_variable *var;
01140 struct ast_vm_user *retval;
01141
01142 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01143 if (!ivm)
01144 ast_set_flag(retval, VM_ALLOCED);
01145 else
01146 memset(retval, 0, sizeof(*retval));
01147 if (mailbox)
01148 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01149 populate_defaults(retval);
01150 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01151 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01152 else
01153 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01154 if (var) {
01155 apply_options_full(retval, var);
01156 ast_variables_destroy(var);
01157 } else {
01158 if (!ivm)
01159 ast_free(retval);
01160 retval = NULL;
01161 }
01162 }
01163 return retval;
01164 }
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01175 {
01176
01177 struct ast_vm_user *vmu=NULL, *cur;
01178 AST_LIST_LOCK(&users);
01179
01180 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01181 context = "default";
01182
01183 AST_LIST_TRAVERSE(&users, cur, list) {
01184 #ifdef IMAP_STORAGE
01185 if (cur->imapversion != imapversion) {
01186 continue;
01187 }
01188 #endif
01189 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01190 break;
01191 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01192 break;
01193 }
01194 if (cur) {
01195
01196 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01197 memcpy(vmu, cur, sizeof(*vmu));
01198 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01199 AST_LIST_NEXT(vmu, list) = NULL;
01200 }
01201 } else
01202 vmu = find_user_realtime(ivm, context, mailbox);
01203 AST_LIST_UNLOCK(&users);
01204 return vmu;
01205 }
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01218 {
01219
01220 struct ast_vm_user *cur;
01221 int res = -1;
01222 AST_LIST_LOCK(&users);
01223 AST_LIST_TRAVERSE(&users, cur, list) {
01224 if ((!context || !strcasecmp(context, cur->context)) &&
01225 (!strcasecmp(mailbox, cur->mailbox)))
01226 break;
01227 }
01228 if (cur) {
01229 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01230 res = 0;
01231 }
01232 AST_LIST_UNLOCK(&users);
01233 return res;
01234 }
01235
01236
01237
01238
01239
01240
01241
01242
01243 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01244 {
01245 struct ast_config *cfg=NULL;
01246 struct ast_variable *var=NULL;
01247 struct ast_category *cat=NULL;
01248 char *category=NULL, *value=NULL, *new=NULL;
01249 const char *tmp=NULL;
01250 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01251 if (!change_password_realtime(vmu, newpassword))
01252 return;
01253
01254
01255 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags))) {
01256 while ((category = ast_category_browse(cfg, category))) {
01257 if (!strcasecmp(category, vmu->context)) {
01258 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01259 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01260 break;
01261 }
01262 value = strstr(tmp,",");
01263 if (!value) {
01264 ast_log(AST_LOG_WARNING, "variable has bad format.\n");
01265 break;
01266 }
01267 new = alloca((strlen(value)+strlen(newpassword)+1));
01268 sprintf(new,"%s%s", newpassword, value);
01269 if (!(cat = ast_category_get(cfg, category))) {
01270 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01271 break;
01272 }
01273 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01274 }
01275 }
01276
01277 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01278 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01279 config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01280 }
01281 category = NULL;
01282 var = NULL;
01283
01284
01285 if ((cfg = ast_config_load("users.conf", config_flags))) {
01286 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01287 while ((category = ast_category_browse(cfg, category))) {
01288 ast_debug(4, "users.conf: %s\n", category);
01289 if (!strcasecmp(category, vmu->mailbox)) {
01290 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01291 ast_debug(3, "looks like we need to make vmsecret!\n");
01292 var = ast_variable_new("vmsecret", newpassword, "");
01293 }
01294 new = alloca(strlen(newpassword)+1);
01295 sprintf(new, "%s", newpassword);
01296 if (!(cat = ast_category_get(cfg, category))) {
01297 ast_debug(4, "failed to get category!\n");
01298 break;
01299 }
01300 if (!var)
01301 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01302 else
01303 ast_variable_append(cat, var);
01304 }
01305 }
01306
01307 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01308 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01309 config_text_file_save("users.conf", cfg, "AppVoicemail");
01310 }
01311 }
01312
01313 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01314 {
01315 char buf[255];
01316 snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
01317 if (!ast_safe_system(buf)) {
01318 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01319
01320 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01321 }
01322 }
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01335 {
01336 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01337 }
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349 static int make_file(char *dest, const int len, const char *dir, const int num)
01350 {
01351 return snprintf(dest, len, "%s/msg%04d", dir, num);
01352 }
01353
01354
01355 static FILE *vm_mkftemp(char *template)
01356 {
01357 FILE *p = NULL;
01358 int pfd = mkstemp(template);
01359 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01360 if (pfd > -1) {
01361 p = fdopen(pfd, "w+");
01362 if (!p) {
01363 close(pfd);
01364 pfd = -1;
01365 }
01366 }
01367 return p;
01368 }
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01379 {
01380 mode_t mode = VOICEMAIL_DIR_MODE;
01381 int res;
01382
01383 make_dir(dest, len, context, ext, folder);
01384 if ((res = ast_mkdir(dest, mode))) {
01385 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01386 return -1;
01387 }
01388 return 0;
01389 }
01390
01391 static const char *mbox(int id)
01392 {
01393 static const char *msgs[] = {
01394 #ifdef IMAP_STORAGE
01395 imapfolder,
01396 #else
01397 "INBOX",
01398 #endif
01399 "Old",
01400 "Work",
01401 "Family",
01402 "Friends",
01403 "Cust1",
01404 "Cust2",
01405 "Cust3",
01406 "Cust4",
01407 "Cust5",
01408 "Deleted",
01409 "Urgent"
01410 };
01411 return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "Unknown";
01412 }
01413
01414 static void free_user(struct ast_vm_user *vmu)
01415 {
01416 if (ast_test_flag(vmu, VM_ALLOCED))
01417 ast_free(vmu);
01418 }
01419
01420
01421
01422 #ifdef IMAP_STORAGE
01423 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01424 {
01425 char arg[10];
01426 struct vm_state *vms;
01427 unsigned long messageNum;
01428
01429
01430 if (msgnum < 0 && !imapgreetings) {
01431 ast_filedelete(file, NULL);
01432 return;
01433 }
01434
01435 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01436 ast_log(LOG_WARNING, "Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->mailbox, msgnum);
01437 return;
01438 }
01439
01440
01441
01442 messageNum = vms->msgArray[msgnum];
01443 if (messageNum == 0) {
01444 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n",msgnum,messageNum);
01445 return;
01446 }
01447 if (option_debug > 2)
01448 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n",msgnum,messageNum);
01449
01450 snprintf (arg, sizeof(arg), "%lu",messageNum);
01451 ast_mutex_lock(&vms->lock);
01452 mail_setflag (vms->mailstream,arg,"\\DELETED");
01453 mail_expunge(vms->mailstream);
01454 ast_mutex_unlock(&vms->lock);
01455 }
01456
01457 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01458 {
01459 struct vm_state *vms_p;
01460 char *file, *filename;
01461 char *attachment;
01462 int ret = 0, i;
01463 BODY *body;
01464
01465
01466
01467
01468 if (msgnum > -1 || !imapgreetings) {
01469 return 0;
01470 } else {
01471 file = strrchr(ast_strdupa(dir), '/');
01472 if (file)
01473 *file++ = '\0';
01474 else {
01475 ast_debug (1, "Failed to procure file name from directory passed.\n");
01476 return -1;
01477 }
01478 }
01479
01480
01481 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01482 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01483
01484
01485
01486
01487 if (!(vms_p = create_vm_state_from_user(vmu))) {
01488 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01489 return -1;
01490 }
01491 }
01492
01493
01494 *vms_p->introfn = '\0';
01495
01496 ast_mutex_lock(&vms_p->lock);
01497 ret = init_mailstream(vms_p, GREETINGS_FOLDER);
01498 if (!vms_p->mailstream) {
01499 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01500 ast_mutex_unlock(&vms_p->lock);
01501 return -1;
01502 }
01503
01504
01505 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01506 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01507
01508 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01509 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01510 } else {
01511 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01512 ast_mutex_unlock(&vms_p->lock);
01513 return -1;
01514 }
01515 filename = strsep(&attachment, ".");
01516 if (!strcmp(filename, file)) {
01517 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01518 vms_p->msgArray[vms_p->curmsg] = i + 1;
01519 save_body(body, vms_p, "2", attachment, 0);
01520 ast_mutex_unlock(&vms_p->lock);
01521 return 0;
01522 }
01523 }
01524 ast_mutex_unlock(&vms_p->lock);
01525
01526 return -1;
01527 }
01528
01529 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01530 {
01531 BODY *body;
01532 char *header_content;
01533 char *attachedfilefmt;
01534 char buf[80];
01535 struct vm_state *vms;
01536 char text_file[PATH_MAX];
01537 FILE *text_file_ptr;
01538 int res = 0;
01539 struct ast_vm_user *vmu;
01540
01541 if (!(vmu = find_user(NULL, context, mailbox))) {
01542 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01543 return -1;
01544 }
01545
01546 if (msgnum < 0) {
01547 if (imapgreetings) {
01548 res = imap_retrieve_greeting(dir, msgnum, vmu);
01549 goto exit;
01550 } else {
01551 res = 0;
01552 goto exit;
01553 }
01554 }
01555
01556
01557
01558
01559 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01560
01561
01562
01563
01564
01565
01566
01567 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01568 res = -1;
01569 goto exit;
01570 }
01571
01572 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01573 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01574
01575
01576 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01577 res = 0;
01578 goto exit;
01579 }
01580
01581 if (option_debug > 2)
01582 ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01583 if (vms->msgArray[msgnum] == 0) {
01584 ast_log (LOG_WARNING,"Trying to access unknown message\n");
01585 res = -1;
01586 goto exit;
01587 }
01588
01589
01590 ast_mutex_lock(&vms->lock);
01591 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01592 ast_mutex_unlock(&vms->lock);
01593
01594 if (ast_strlen_zero(header_content)) {
01595 ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[msgnum]);
01596 res = -1;
01597 goto exit;
01598 }
01599
01600 ast_mutex_lock(&vms->lock);
01601 mail_fetchstructure (vms->mailstream,vms->msgArray[msgnum],&body);
01602 ast_mutex_unlock(&vms->lock);
01603
01604
01605 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01606 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01607 } else {
01608 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01609 res = -1;
01610 goto exit;
01611 }
01612
01613
01614
01615 strsep(&attachedfilefmt, ".");
01616 if (!attachedfilefmt) {
01617 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01618 res = -1;
01619 goto exit;
01620 }
01621
01622 save_body(body, vms, "2", attachedfilefmt, 0);
01623 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01624 *vms->introfn = '\0';
01625 }
01626
01627
01628 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01629
01630 if (!(text_file_ptr = fopen(text_file, "w"))) {
01631 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01632 }
01633
01634 fprintf(text_file_ptr, "%s\n", "[message]");
01635
01636 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01637 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01638 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01639 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01640 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01641 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
01642 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
01643 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
01644 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
01645 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
01646 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
01647 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
01648 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
01649 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
01650 fclose(text_file_ptr);
01651
01652 exit:
01653 free_user(vmu);
01654 return res;
01655 }
01656
01657 static int folder_int(const char *folder)
01658 {
01659
01660 if (!folder)
01661 return 0;
01662 #ifdef IMAP_STORAGE
01663 if (!strcasecmp(folder, imapfolder))
01664 #else
01665 if (!strcasecmp(folder, "INBOX"))
01666 #endif
01667 return 0;
01668 else if (!strcasecmp(folder, "Old"))
01669 return 1;
01670 else if (!strcasecmp(folder, "Work"))
01671 return 2;
01672 else if (!strcasecmp(folder, "Family"))
01673 return 3;
01674 else if (!strcasecmp(folder, "Friends"))
01675 return 4;
01676 else if (!strcasecmp(folder, "Cust1"))
01677 return 5;
01678 else if (!strcasecmp(folder, "Cust2"))
01679 return 6;
01680 else if (!strcasecmp(folder, "Cust3"))
01681 return 7;
01682 else if (!strcasecmp(folder, "Cust4"))
01683 return 8;
01684 else if (!strcasecmp(folder, "Cust5"))
01685 return 9;
01686 else
01687 return 0;
01688 }
01689
01690 static int __messagecount(const char *context, const char *mailbox, const char *folder)
01691 {
01692 SEARCHPGM *pgm;
01693 SEARCHHEADER *hdr;
01694
01695 struct ast_vm_user *vmu, vmus;
01696 struct vm_state *vms_p;
01697 int ret = 0;
01698 int fold = folder_int(folder);
01699 int urgent = 0;
01700
01701
01702 if (fold == 11) {
01703 fold = NEW_FOLDER;
01704 urgent = 1;
01705 }
01706
01707 if (ast_strlen_zero(mailbox))
01708 return 0;
01709
01710
01711 vmu = find_user(&vmus, context, mailbox);
01712 if (!vmu) {
01713 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
01714 return -1;
01715 } else {
01716
01717 if (vmu->imapuser[0] == '\0') {
01718 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
01719 return -1;
01720 }
01721 }
01722
01723
01724 if (vmu->imapuser[0] == '\0') {
01725 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
01726 free_user(vmu);
01727 return -1;
01728 }
01729
01730
01731 vms_p = get_vm_state_by_imapuser(vmu->imapuser,1);
01732 if (!vms_p) {
01733 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
01734 }
01735 if (vms_p) {
01736 ast_debug(3, "Returning before search - user is logged in\n");
01737 if (fold == 0) {
01738 return vms_p->newmessages;
01739 }
01740 if (fold == 1) {
01741 return vms_p->oldmessages;
01742 }
01743 if (fold == 11) {
01744 return vms_p->urgentmessages;
01745 }
01746 }
01747
01748
01749 vms_p = get_vm_state_by_imapuser(vmu->imapuser,0);
01750 if (!vms_p) {
01751 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
01752 }
01753
01754 if (!vms_p) {
01755 vms_p = create_vm_state_from_user(vmu);
01756 }
01757 ret = init_mailstream(vms_p, fold);
01758 if (!vms_p->mailstream) {
01759 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
01760 return -1;
01761 }
01762 if (ret == 0) {
01763 ast_mutex_lock(&vms_p->lock);
01764 pgm = mail_newsearchpgm ();
01765 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
01766 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
01767 pgm->header = hdr;
01768 if (fold != 1) {
01769 pgm->unseen = 1;
01770 pgm->seen = 0;
01771 }
01772
01773
01774
01775 else {
01776 pgm->unseen = 0;
01777 pgm->seen = 1;
01778 }
01779
01780 if (urgent) {
01781 pgm->flagged = 1;
01782 pgm->unflagged = 0;
01783 }
01784 pgm->undeleted = 1;
01785 pgm->deleted = 0;
01786
01787 vms_p->vmArrayIndex = 0;
01788 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
01789 if (fold == 0 && urgent == 0)
01790 vms_p->newmessages = vms_p->vmArrayIndex;
01791 if (fold == 1)
01792 vms_p->oldmessages = vms_p->vmArrayIndex;
01793 if (fold == 0 && urgent == 1)
01794 vms_p->urgentmessages = vms_p->vmArrayIndex;
01795
01796 mail_free_searchpgm(&pgm);
01797 ast_mutex_unlock(&vms_p->lock);
01798 vms_p->updated = 0;
01799 return vms_p->vmArrayIndex;
01800 } else {
01801 ast_mutex_lock(&vms_p->lock);
01802 mail_ping(vms_p->mailstream);
01803 ast_mutex_unlock(&vms_p->lock);
01804 }
01805 return 0;
01806 }
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817 static int messagecount(const char *context, const char *mailbox, const char *folder)
01818 {
01819 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
01820 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
01821 } else {
01822 return __messagecount(context, mailbox, folder);
01823 }
01824 }
01825
01826 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag)
01827 {
01828 char *myserveremail = serveremail;
01829 char fn[PATH_MAX];
01830 char introfn[PATH_MAX];
01831 char mailbox[256];
01832 char *stringp;
01833 FILE *p=NULL;
01834 char tmp[80] = "/tmp/astmail-XXXXXX";
01835 long len;
01836 void *buf;
01837 int tempcopy = 0;
01838 STRING str;
01839 int ret;
01840 char *imap_flags = NIL;
01841
01842
01843 if (msgnum < 0 && !imapgreetings) {
01844 return 0;
01845 }
01846
01847
01848 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
01849 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
01850 imap_flags="\\FLAGGED";
01851 }
01852
01853
01854 fmt = ast_strdupa(fmt);
01855 stringp = fmt;
01856 strsep(&stringp, "|");
01857
01858 if (!ast_strlen_zero(vmu->serveremail))
01859 myserveremail = vmu->serveremail;
01860
01861 if (msgnum > -1)
01862 make_file(fn, sizeof(fn), dir, msgnum);
01863 else
01864 ast_copy_string (fn, dir, sizeof(fn));
01865
01866 snprintf(introfn, sizeof(introfn), "%sintro", fn);
01867 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
01868 *introfn = '\0';
01869 }
01870
01871 if (ast_strlen_zero(vmu->email)) {
01872
01873
01874
01875
01876
01877 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
01878 tempcopy = 1;
01879 }
01880
01881 if (!strcmp(fmt, "wav49"))
01882 fmt = "WAV";
01883 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
01884
01885
01886
01887 if (!(p = vm_mkftemp(tmp))) {
01888 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
01889 if (tempcopy)
01890 *(vmu->email) = '\0';
01891 return -1;
01892 }
01893
01894 if (msgnum < 0 && imapgreetings) {
01895 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
01896 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
01897 return -1;
01898 }
01899 imap_delete_old_greeting(fn, vms);
01900 }
01901
01902 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX", S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
01903
01904 len = ftell(p);
01905 rewind(p);
01906 if (!(buf = ast_malloc(len + 1))) {
01907 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
01908 fclose(p);
01909 if (tempcopy)
01910 *(vmu->email) = '\0';
01911 return -1;
01912 }
01913 if (fread(buf, len, 1, p) < len) {
01914 if (ferror(p)) {
01915 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
01916 return -1;
01917 }
01918 }
01919 ((char *)buf)[len] = '\0';
01920 INIT(&str, mail_string, buf, len);
01921 ret = init_mailstream(vms, NEW_FOLDER);
01922 if (ret == 0) {
01923 imap_mailbox_name(mailbox, sizeof(mailbox), vms, NEW_FOLDER, 1);
01924 ast_mutex_lock(&vms->lock);
01925 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
01926 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
01927 ast_mutex_unlock(&vms->lock);
01928 fclose(p);
01929 unlink(tmp);
01930 ast_free(buf);
01931 } else {
01932 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n",mailbox);
01933 fclose(p);
01934 unlink(tmp);
01935 ast_free(buf);
01936 return -1;
01937 }
01938 ast_debug(3, "%s stored\n", fn);
01939
01940 if (tempcopy)
01941 *(vmu->email) = '\0';
01942
01943 return 0;
01944
01945 }
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
01961 {
01962 char tmp[PATH_MAX] = "";
01963 char *mailboxnc;
01964 char *context;
01965 char *mb;
01966 char *cur;
01967 if (newmsgs)
01968 *newmsgs = 0;
01969 if (oldmsgs)
01970 *oldmsgs = 0;
01971 if (urgentmsgs)
01972 *urgentmsgs = 0;
01973
01974 ast_debug(3,"Mailbox is set to %s\n",mailbox_context);
01975
01976 if (ast_strlen_zero(mailbox_context))
01977 return 0;
01978
01979 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01980 context = strchr(tmp, '@');
01981 if (strchr(mailbox_context, ',')) {
01982 int tmpnew, tmpold, tmpurgent;
01983 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01984 mb = tmp;
01985 while ((cur = strsep(&mb, ", "))) {
01986 if (!ast_strlen_zero(cur)) {
01987 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
01988 return -1;
01989 else {
01990 if (newmsgs)
01991 *newmsgs += tmpnew;
01992 if (oldmsgs)
01993 *oldmsgs += tmpold;
01994 if (urgentmsgs)
01995 *urgentmsgs += tmpurgent;
01996 }
01997 }
01998 }
01999 return 0;
02000 }
02001 if (context) {
02002 *context = '\0';
02003 mailboxnc = tmp;
02004 context++;
02005 } else {
02006 context = "default";
02007 mailboxnc = (char *)mailbox_context;
02008 }
02009 if (newmsgs) {
02010 if ((*newmsgs = __messagecount(context, mailboxnc, imapfolder)) < 0) {
02011 return -1;
02012 }
02013 }
02014 if (oldmsgs) {
02015 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02016 return -1;
02017 }
02018 }
02019 if (urgentmsgs) {
02020 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02021 return -1;
02022 }
02023 }
02024 return 0;
02025 }
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037 static int has_voicemail(const char *mailbox, const char *folder)
02038 {
02039 char tmp[256], *tmp2, *box, *context;
02040 ast_copy_string(tmp, mailbox, sizeof(tmp));
02041 tmp2 = tmp;
02042 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02043 while ((box = strsep(&tmp2, ",&"))) {
02044 if (!ast_strlen_zero(box)) {
02045 if (has_voicemail(box, folder)) {
02046 return 1;
02047 }
02048 }
02049 }
02050 }
02051 if ((context = strchr(tmp, '@'))) {
02052 *context++ = '\0';
02053 } else {
02054 context = "default";
02055 }
02056 return __messagecount(context, tmp, folder) ? 1 : 0;
02057 }
02058
02059
02060
02061
02062
02063
02064
02065
02066
02067
02068
02069
02070
02071
02072
02073
02074 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, char *flag)
02075 {
02076 struct vm_state *sendvms = NULL, *destvms = NULL;
02077 char messagestring[10];
02078 if (msgnum >= recip->maxmsg) {
02079 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02080 return -1;
02081 }
02082 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02083 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02084 return -1;
02085 }
02086 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02087 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02088 return -1;
02089 }
02090 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02091 ast_mutex_lock(&sendvms->lock);
02092 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(imbox)) == T)) {
02093 ast_mutex_unlock(&sendvms->lock);
02094 return 0;
02095 }
02096 ast_mutex_unlock(&sendvms->lock);
02097 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02098 return -1;
02099 }
02100
02101 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02102 {
02103 char tmp[256], *t = tmp;
02104 size_t left = sizeof(tmp);
02105
02106 if (box == OLD_FOLDER) {
02107 ast_copy_string(vms->curbox, mbox(NEW_FOLDER), sizeof(vms->curbox));
02108 } else {
02109 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
02110 }
02111
02112 if (box == NEW_FOLDER) {
02113 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02114 } else {
02115 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(box));
02116 }
02117
02118
02119 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02120
02121
02122 if (!ast_strlen_zero(authuser))
02123 ast_build_string(&t, &left, "/authuser=%s", authuser);
02124
02125
02126 if (!ast_strlen_zero(imapflags))
02127 ast_build_string(&t, &left, "/%s", imapflags);
02128
02129
02130 #if 1
02131 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02132 #else
02133 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02134 #endif
02135 if (box == NEW_FOLDER || box == OLD_FOLDER)
02136 snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX");
02137 else if (box == GREETINGS_FOLDER)
02138 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02139 else {
02140 if (!ast_strlen_zero(imapparentfolder)) {
02141
02142 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(box));
02143 } else {
02144 snprintf(spec, len, "%s%s", tmp, mbox(box));
02145 }
02146 }
02147 }
02148
02149 static int init_mailstream(struct vm_state *vms, int box)
02150 {
02151 MAILSTREAM *stream = NIL;
02152 long debug;
02153 char tmp[256];
02154
02155 if (!vms) {
02156 ast_log (LOG_ERROR,"vm_state is NULL!\n");
02157 return -1;
02158 }
02159 if (option_debug > 2)
02160 ast_log (LOG_DEBUG,"vm_state user is:%s\n",vms->imapuser);
02161 if (vms->mailstream == NIL || !vms->mailstream) {
02162 if (option_debug)
02163 ast_log (LOG_DEBUG,"mailstream not set.\n");
02164 } else {
02165 stream = vms->mailstream;
02166 }
02167
02168 debug = NIL;
02169
02170 if (delimiter == '\0') {
02171 char *cp;
02172 #ifdef USE_SYSTEM_IMAP
02173 #include <imap/linkage.c>
02174 #elif defined(USE_SYSTEM_CCLIENT)
02175 #include <c-client/linkage.c>
02176 #else
02177 #include "linkage.c"
02178 #endif
02179
02180 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02181 ast_mutex_lock(&vms->lock);
02182 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02183 ast_mutex_unlock(&vms->lock);
02184 if (stream == NIL) {
02185 ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02186 return -1;
02187 }
02188 get_mailbox_delimiter(stream);
02189
02190 for (cp = imapfolder; *cp; cp++)
02191 if (*cp == '/')
02192 *cp = delimiter;
02193 }
02194
02195 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02196 if (option_debug > 2)
02197 ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box);
02198 ast_mutex_lock(&vms->lock);
02199 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02200 ast_mutex_unlock(&vms->lock);
02201 if (vms->mailstream == NIL) {
02202 return -1;
02203 } else {
02204 return 0;
02205 }
02206 }
02207
02208 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02209 {
02210 SEARCHPGM *pgm;
02211 SEARCHHEADER *hdr;
02212 int ret, urgent = 0;
02213
02214
02215 if (box == 11) {
02216 box = NEW_FOLDER;
02217 urgent = 1;
02218 }
02219
02220 ast_copy_string(vms->imapuser,vmu->imapuser, sizeof(vms->imapuser));
02221 ast_debug(3,"Before init_mailstream, user is %s\n",vmu->imapuser);
02222 vms->imapversion = vmu->imapversion;
02223
02224 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02225 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02226 return -1;
02227 }
02228
02229 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02230
02231
02232 if (box == 0) {
02233 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(box));
02234 check_quota(vms,(char *)mbox(box));
02235 }
02236
02237 ast_mutex_lock(&vms->lock);
02238 pgm = mail_newsearchpgm();
02239
02240
02241 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02242 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02243 pgm->header = hdr;
02244 pgm->deleted = 0;
02245 pgm->undeleted = 1;
02246
02247
02248 if (box == NEW_FOLDER && urgent == 1) {
02249 pgm->unseen = 1;
02250 pgm->seen = 0;
02251 pgm->flagged = 1;
02252 pgm->unflagged = 0;
02253 } else if (box == NEW_FOLDER && urgent == 0) {
02254 pgm->unseen = 1;
02255 pgm->seen = 0;
02256 pgm->flagged = 0;
02257 pgm->unflagged = 1;
02258 } else if (box == OLD_FOLDER) {
02259 pgm->seen = 1;
02260 pgm->unseen = 0;
02261 }
02262
02263 ast_debug(3,"Before mail_search_full, user is %s\n",vmu->imapuser);
02264
02265 vms->vmArrayIndex = 0;
02266 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02267 vms->lastmsg = vms->vmArrayIndex - 1;
02268 mail_free_searchpgm(&pgm);
02269
02270 ast_mutex_unlock(&vms->lock);
02271 return 0;
02272 }
02273
02274 static void write_file(char *filename, char *buffer, unsigned long len)
02275 {
02276 FILE *output;
02277
02278 output = fopen (filename, "w");
02279 if (fwrite(buffer, len, 1, output) != 1) {
02280 if (ferror(output)) {
02281 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02282 }
02283 }
02284 fclose (output);
02285 }
02286
02287 static void update_messages_by_imapuser(const char *user, unsigned long number)
02288 {
02289 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02290
02291 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02292 return;
02293 }
02294
02295 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02296 vms->msgArray[vms->vmArrayIndex++] = number;
02297 }
02298
02299 void mm_searched(MAILSTREAM *stream, unsigned long number)
02300 {
02301 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02302
02303 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02304 return;
02305
02306 update_messages_by_imapuser(user, number);
02307 }
02308
02309 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02310 {
02311 struct ast_variable *var;
02312 struct ast_vm_user *vmu;
02313
02314 vmu = ast_calloc(1, sizeof *vmu);
02315 if (!vmu)
02316 return NULL;
02317 ast_set_flag(vmu, VM_ALLOCED);
02318 populate_defaults(vmu);
02319
02320 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02321 if (var) {
02322 apply_options_full(vmu, var);
02323 ast_variables_destroy(var);
02324 return vmu;
02325 } else {
02326 ast_free(vmu);
02327 return NULL;
02328 }
02329 }
02330
02331
02332
02333 void mm_exists(MAILSTREAM * stream, unsigned long number)
02334 {
02335
02336 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02337 if (number == 0) return;
02338 set_update(stream);
02339 }
02340
02341
02342 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02343 {
02344
02345 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02346 if (number == 0) return;
02347 set_update(stream);
02348 }
02349
02350
02351 void mm_flags(MAILSTREAM * stream, unsigned long number)
02352 {
02353
02354 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02355 if (number == 0) return;
02356 set_update(stream);
02357 }
02358
02359
02360 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02361 {
02362 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02363 mm_log (string, errflg);
02364 }
02365
02366
02367 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02368 {
02369 if (delimiter == '\0') {
02370 delimiter = delim;
02371 }
02372
02373 ast_debug(5, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
02374 if (attributes & LATT_NOINFERIORS)
02375 ast_debug(5, "no inferiors\n");
02376 if (attributes & LATT_NOSELECT)
02377 ast_debug(5, "no select\n");
02378 if (attributes & LATT_MARKED)
02379 ast_debug(5, "marked\n");
02380 if (attributes & LATT_UNMARKED)
02381 ast_debug(5, "unmarked\n");
02382 }
02383
02384
02385 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02386 {
02387 ast_debug(5, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
02388 if (attributes & LATT_NOINFERIORS)
02389 ast_debug(5, "no inferiors\n");
02390 if (attributes & LATT_NOSELECT)
02391 ast_debug(5, "no select\n");
02392 if (attributes & LATT_MARKED)
02393 ast_debug(5, "marked\n");
02394 if (attributes & LATT_UNMARKED)
02395 ast_debug(5, "unmarked\n");
02396 }
02397
02398
02399 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02400 {
02401 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02402 if (status->flags & SA_MESSAGES)
02403 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02404 if (status->flags & SA_RECENT)
02405 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02406 if (status->flags & SA_UNSEEN)
02407 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02408 if (status->flags & SA_UIDVALIDITY)
02409 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02410 if (status->flags & SA_UIDNEXT)
02411 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02412 ast_log(AST_LOG_NOTICE, "\n");
02413 }
02414
02415
02416 void mm_log(char *string, long errflg)
02417 {
02418 switch ((short) errflg) {
02419 case NIL:
02420 ast_debug(1,"IMAP Info: %s\n", string);
02421 break;
02422 case PARSE:
02423 case WARN:
02424 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02425 break;
02426 case ERROR:
02427 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02428 break;
02429 }
02430 }
02431
02432
02433 void mm_dlog(char *string)
02434 {
02435 ast_log(AST_LOG_NOTICE, "%s\n", string);
02436 }
02437
02438
02439 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02440 {
02441 struct ast_vm_user *vmu;
02442
02443 ast_debug(4, "Entering callback mm_login\n");
02444
02445 ast_copy_string(user, mb->user, MAILTMPLEN);
02446
02447
02448 if (!ast_strlen_zero(authpassword)) {
02449 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02450 } else {
02451 AST_LIST_TRAVERSE(&users, vmu, list) {
02452 if (!strcasecmp(mb->user, vmu->imapuser)) {
02453 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02454 break;
02455 }
02456 }
02457 if (!vmu) {
02458 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02459 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02460 free_user(vmu);
02461 }
02462 }
02463 }
02464 }
02465
02466
02467 void mm_critical(MAILSTREAM * stream)
02468 {
02469 }
02470
02471
02472 void mm_nocritical(MAILSTREAM * stream)
02473 {
02474 }
02475
02476
02477 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02478 {
02479 kill (getpid (), SIGSTOP);
02480 return NIL;
02481 }
02482
02483
02484 void mm_fatal(char *string)
02485 {
02486 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02487 }
02488
02489
02490 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02491 {
02492 struct vm_state *vms;
02493 char *mailbox = stream->mailbox, *user;
02494 char buf[1024] = "";
02495 unsigned long usage = 0, limit = 0;
02496
02497 while (pquota) {
02498 usage = pquota->usage;
02499 limit = pquota->limit;
02500 pquota = pquota->next;
02501 }
02502
02503 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || (!(vms = get_vm_state_by_imapuser(user, 2)) && !(vms = get_vm_state_by_imapuser(user, 0)))) {
02504 ast_log(AST_LOG_ERROR, "No state found.\n");
02505 return;
02506 }
02507
02508 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02509
02510 vms->quota_usage = usage;
02511 vms->quota_limit = limit;
02512 }
02513
02514 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02515 {
02516 char *start, *eol_pnt;
02517 int taglen;
02518
02519 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02520 return NULL;
02521
02522 taglen = strlen(tag) + 1;
02523 if (taglen < 1)
02524 return NULL;
02525
02526 if (!(start = strstr(header, tag)))
02527 return NULL;
02528
02529
02530 memset(buf, 0, len);
02531
02532 ast_copy_string(buf, start+taglen, len);
02533 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02534 *eol_pnt = '\0';
02535 return buf;
02536 }
02537
02538 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02539 {
02540 char *start, *quote, *eol_pnt;
02541
02542 if (ast_strlen_zero(mailbox))
02543 return NULL;
02544
02545 if (!(start = strstr(mailbox, "/user=")))
02546 return NULL;
02547
02548 ast_copy_string(buf, start+6, len);
02549
02550 if (!(quote = strchr(buf, '\"'))) {
02551 if (!(eol_pnt = strchr(buf, '/')))
02552 eol_pnt = strchr(buf,'}');
02553 *eol_pnt = '\0';
02554 return buf;
02555 } else {
02556 eol_pnt = strchr(buf+1,'\"');
02557 *eol_pnt = '\0';
02558 return buf+1;
02559 }
02560 }
02561
02562 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02563 {
02564 struct vm_state *vms_p;
02565
02566 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02567 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02568 return vms_p;
02569 }
02570 if (option_debug > 4)
02571 ast_log(AST_LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser);
02572 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02573 return NULL;
02574 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02575 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02576 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02577 vms_p->mailstream = NIL;
02578 vms_p->imapversion = vmu->imapversion;
02579 if (option_debug > 4)
02580 ast_log(AST_LOG_DEBUG,"Copied %s to %s\n",vmu->imapuser,vms_p->imapuser);
02581 vms_p->updated = 1;
02582
02583 ast_copy_string(vms_p->curbox, mbox(0), sizeof(vms_p->curbox));
02584 init_vm_state(vms_p);
02585 vmstate_insert(vms_p);
02586 return vms_p;
02587 }
02588
02589 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
02590 {
02591 struct vmstate *vlist = NULL;
02592
02593 if (interactive) {
02594 struct vm_state *vms;
02595 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02596 vms = pthread_getspecific(ts_vmstate.key);
02597 return vms;
02598 }
02599
02600 AST_LIST_LOCK(&vmstates);
02601 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02602 if (!vlist->vms) {
02603 ast_debug(3, "error: vms is NULL for %s\n", user);
02604 continue;
02605 }
02606 if (vlist->vms->imapversion != imapversion) {
02607 continue;
02608 }
02609 if (!vlist->vms->imapuser) {
02610 ast_debug(3, "error: imapuser is NULL for %s\n", user);
02611 continue;
02612 }
02613
02614 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
02615 AST_LIST_UNLOCK(&vmstates);
02616 return vlist->vms;
02617 }
02618 }
02619 AST_LIST_UNLOCK(&vmstates);
02620
02621 ast_debug(3, "%s not found in vmstates\n", user);
02622
02623 return NULL;
02624 }
02625
02626 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
02627 {
02628
02629 struct vmstate *vlist = NULL;
02630 const char *local_context = S_OR(context, "default");
02631
02632 if (interactive) {
02633 struct vm_state *vms;
02634 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02635 vms = pthread_getspecific(ts_vmstate.key);
02636 return vms;
02637 }
02638
02639 AST_LIST_LOCK(&vmstates);
02640 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02641 if (!vlist->vms) {
02642 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
02643 continue;
02644 }
02645 if (vlist->vms->imapversion != imapversion) {
02646 continue;
02647 }
02648 if (!vlist->vms->username || !vlist->vms->context) {
02649 ast_debug(3, "error: username is NULL for %s\n", mailbox);
02650 continue;
02651 }
02652
02653 ast_debug(3, "comparing mailbox %s@%s (i=%d) to vmstate mailbox %s@%s (i=%d)\n", mailbox, local_context, interactive, vlist->vms->username, vlist->vms->context, vlist->vms->interactive);
02654
02655 if (!strcmp(vlist->vms->username,mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
02656 ast_debug(3, "Found it!\n");
02657 AST_LIST_UNLOCK(&vmstates);
02658 return vlist->vms;
02659 }
02660 }
02661 AST_LIST_UNLOCK(&vmstates);
02662
02663 ast_debug(3, "%s not found in vmstates\n", mailbox);
02664
02665 return NULL;
02666 }
02667
02668 static void vmstate_insert(struct vm_state *vms)
02669 {
02670 struct vmstate *v;
02671 struct vm_state *altvms;
02672
02673
02674
02675
02676 if (vms->interactive == 1) {
02677 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
02678 if (altvms) {
02679 ast_debug(3, "Duplicate mailbox %s, copying message info...\n",vms->username);
02680 vms->newmessages = altvms->newmessages;
02681 vms->oldmessages = altvms->oldmessages;
02682 vms->vmArrayIndex = altvms->vmArrayIndex;
02683 vms->lastmsg = altvms->lastmsg;
02684 vms->curmsg = altvms->curmsg;
02685
02686 vms->persist_vms = altvms;
02687
02688 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
02689 vms->mailstream = altvms->mailstream;
02690 #else
02691 vms->mailstream = NIL;
02692 #endif
02693 }
02694 return;
02695 }
02696
02697 if (!(v = ast_calloc(1, sizeof(*v))))
02698 return;
02699
02700 v->vms = vms;
02701
02702 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02703
02704 AST_LIST_LOCK(&vmstates);
02705 AST_LIST_INSERT_TAIL(&vmstates, v, list);
02706 AST_LIST_UNLOCK(&vmstates);
02707 }
02708
02709 static void vmstate_delete(struct vm_state *vms)
02710 {
02711 struct vmstate *vc = NULL;
02712 struct vm_state *altvms = NULL;
02713
02714
02715
02716 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
02717 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
02718 altvms->newmessages = vms->newmessages;
02719 altvms->oldmessages = vms->oldmessages;
02720 altvms->updated = 1;
02721 vms->mailstream = mail_close(vms->mailstream);
02722
02723
02724 return;
02725 }
02726
02727 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
02728
02729 AST_LIST_LOCK(&vmstates);
02730 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
02731 if (vc->vms == vms) {
02732 AST_LIST_REMOVE_CURRENT(list);
02733 break;
02734 }
02735 }
02736 AST_LIST_TRAVERSE_SAFE_END
02737 AST_LIST_UNLOCK(&vmstates);
02738
02739 if (vc) {
02740 ast_mutex_destroy(&vc->vms->lock);
02741 ast_free(vc);
02742 }
02743 else
02744 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
02745 }
02746
02747 static void set_update(MAILSTREAM * stream)
02748 {
02749 struct vm_state *vms;
02750 char *mailbox = stream->mailbox, *user;
02751 char buf[1024] = "";
02752
02753 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
02754 if (user && option_debug > 2)
02755 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
02756 return;
02757 }
02758
02759 ast_debug(3, "User %s mailbox set for update.\n", user);
02760
02761 vms->updated = 1;
02762 }
02763
02764 static void init_vm_state(struct vm_state *vms)
02765 {
02766 int x;
02767 vms->vmArrayIndex = 0;
02768 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
02769 vms->msgArray[x] = 0;
02770 }
02771 ast_mutex_init(&vms->lock);
02772 }
02773
02774 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
02775 {
02776 char *body_content;
02777 char *body_decoded;
02778 char *fn = is_intro ? vms->introfn : vms->fn;
02779 unsigned long len;
02780 unsigned long newlen;
02781 char filename[256];
02782
02783 if (!body || body == NIL)
02784 return -1;
02785
02786 ast_mutex_lock(&vms->lock);
02787 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
02788 ast_mutex_unlock(&vms->lock);
02789 if (body_content != NIL) {
02790 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
02791
02792 body_decoded = rfc822_base64((unsigned char *)body_content, len, &newlen);
02793
02794 if (!newlen) {
02795 return -1;
02796 }
02797 write_file(filename, (char *) body_decoded, newlen);
02798 } else {
02799 ast_debug(5, "Body of message is NULL.\n");
02800 return -1;
02801 }
02802 return 0;
02803 }
02804
02805
02806
02807
02808
02809
02810
02811
02812 static void get_mailbox_delimiter(MAILSTREAM *stream) {
02813 char tmp[50];
02814 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
02815 mail_list(stream, tmp, "*");
02816 }
02817
02818
02819
02820
02821
02822
02823
02824
02825 static void check_quota(struct vm_state *vms, char *mailbox) {
02826 ast_mutex_lock(&vms->lock);
02827 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
02828 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
02829 if (vms && vms->mailstream != NULL) {
02830 imap_getquotaroot(vms->mailstream, mailbox);
02831 } else {
02832 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
02833 }
02834 ast_mutex_unlock(&vms->lock);
02835 }
02836
02837 #endif
02838
02839
02840
02841
02842
02843 static int vm_lock_path(const char *path)
02844 {
02845 switch (ast_lock_path(path)) {
02846 case AST_LOCK_TIMEOUT:
02847 return -1;
02848 default:
02849 return 0;
02850 }
02851 }
02852
02853
02854 #ifdef ODBC_STORAGE
02855 struct generic_prepare_struct {
02856 char *sql;
02857 int argc;
02858 char **argv;
02859 };
02860
02861 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
02862 {
02863 struct generic_prepare_struct *gps = data;
02864 int res, i;
02865 SQLHSTMT stmt;
02866
02867 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02868 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02869 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
02870 return NULL;
02871 }
02872 res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS);
02873 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02874 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
02875 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02876 return NULL;
02877 }
02878 for (i = 0; i < gps->argc; i++)
02879 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
02880
02881 return stmt;
02882 }
02883
02884
02885
02886
02887
02888
02889
02890
02891
02892
02893
02894
02895
02896
02897
02898 static int retrieve_file(char *dir, int msgnum)
02899 {
02900 int x = 0;
02901 int res;
02902 int fd=-1;
02903 size_t fdlen = 0;
02904 void *fdm = MAP_FAILED;
02905 SQLSMALLINT colcount=0;
02906 SQLHSTMT stmt;
02907 char sql[PATH_MAX];
02908 char fmt[80]="";
02909 char *c;
02910 char coltitle[256];
02911 SQLSMALLINT collen;
02912 SQLSMALLINT datatype;
02913 SQLSMALLINT decimaldigits;
02914 SQLSMALLINT nullable;
02915 SQLULEN colsize;
02916 SQLLEN colsize2;
02917 FILE *f=NULL;
02918 char rowdata[80];
02919 char fn[PATH_MAX];
02920 char full_fn[PATH_MAX];
02921 char msgnums[80];
02922 char *argv[] = { dir, msgnums };
02923 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02924
02925 struct odbc_obj *obj;
02926 obj = ast_odbc_request_obj(odbc_database, 0);
02927 if (obj) {
02928 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02929 c = strchr(fmt, '|');
02930 if (c)
02931 *c = '\0';
02932 if (!strcasecmp(fmt, "wav49"))
02933 strcpy(fmt, "WAV");
02934 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
02935 if (msgnum > -1)
02936 make_file(fn, sizeof(fn), dir, msgnum);
02937 else
02938 ast_copy_string(fn, dir, sizeof(fn));
02939
02940
02941 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02942
02943 if (!(f = fopen(full_fn, "w+"))) {
02944 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
02945 goto yuck;
02946 }
02947
02948 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02949 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02950 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02951 if (!stmt) {
02952 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02953 ast_odbc_release_obj(obj);
02954 goto yuck;
02955 }
02956 res = SQLFetch(stmt);
02957 if (res == SQL_NO_DATA) {
02958 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02959 ast_odbc_release_obj(obj);
02960 goto yuck;
02961 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02962 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02963 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02964 ast_odbc_release_obj(obj);
02965 goto yuck;
02966 }
02967 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
02968 if (fd < 0) {
02969 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
02970 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02971 ast_odbc_release_obj(obj);
02972 goto yuck;
02973 }
02974 res = SQLNumResultCols(stmt, &colcount);
02975 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02976 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
02977 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02978 ast_odbc_release_obj(obj);
02979 goto yuck;
02980 }
02981 if (f)
02982 fprintf(f, "[message]\n");
02983 for (x=0;x<colcount;x++) {
02984 rowdata[0] = '\0';
02985 collen = sizeof(coltitle);
02986 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
02987 &datatype, &colsize, &decimaldigits, &nullable);
02988 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02989 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
02990 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02991 ast_odbc_release_obj(obj);
02992 goto yuck;
02993 }
02994 if (!strcasecmp(coltitle, "recording")) {
02995 off_t offset;
02996 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
02997 fdlen = colsize2;
02998 if (fd > -1) {
02999 char tmp[1]="";
03000 lseek(fd, fdlen - 1, SEEK_SET);
03001 if (write(fd, tmp, 1) != 1) {
03002 close(fd);
03003 fd = -1;
03004 continue;
03005 }
03006
03007 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03008 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03009 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03010 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03011 ast_odbc_release_obj(obj);
03012 goto yuck;
03013 } else {
03014 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03015 munmap(fdm, CHUNKSIZE);
03016 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03017 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03018 unlink(full_fn);
03019 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03020 ast_odbc_release_obj(obj);
03021 goto yuck;
03022 }
03023 }
03024 }
03025 if (truncate(full_fn, fdlen) < 0) {
03026 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03027 }
03028 }
03029 } else {
03030 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03031 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03032 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03033 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03034 ast_odbc_release_obj(obj);
03035 goto yuck;
03036 }
03037 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03038 fprintf(f, "%s=%s\n", coltitle, rowdata);
03039 }
03040 }
03041 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03042 ast_odbc_release_obj(obj);
03043 } else
03044 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03045 yuck:
03046 if (f)
03047 fclose(f);
03048 if (fd > -1)
03049 close(fd);
03050 return x - 1;
03051 }
03052
03053
03054
03055
03056
03057
03058
03059
03060
03061
03062
03063 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03064 {
03065 int x = 0;
03066 int res;
03067 SQLHSTMT stmt;
03068 char sql[PATH_MAX];
03069 char rowdata[20];
03070 char *argv[] = { dir };
03071 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03072
03073 struct odbc_obj *obj;
03074 obj = ast_odbc_request_obj(odbc_database, 0);
03075 if (obj) {
03076 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?",odbc_table);
03077 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03078 if (!stmt) {
03079 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03080 ast_odbc_release_obj(obj);
03081 goto yuck;
03082 }
03083 res = SQLFetch(stmt);
03084 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03085 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03086 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03087 ast_odbc_release_obj(obj);
03088 goto yuck;
03089 }
03090 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03091 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03092 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03093 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03094 ast_odbc_release_obj(obj);
03095 goto yuck;
03096 }
03097 if (sscanf(rowdata, "%30d", &x) != 1)
03098 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03099 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03100 ast_odbc_release_obj(obj);
03101 } else
03102 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03103 yuck:
03104 return x - 1;
03105 }
03106
03107
03108
03109
03110
03111
03112
03113
03114
03115
03116 static int message_exists(char *dir, int msgnum)
03117 {
03118 int x = 0;
03119 int res;
03120 SQLHSTMT stmt;
03121 char sql[PATH_MAX];
03122 char rowdata[20];
03123 char msgnums[20];
03124 char *argv[] = { dir, msgnums };
03125 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03126
03127 struct odbc_obj *obj;
03128 obj = ast_odbc_request_obj(odbc_database, 0);
03129 if (obj) {
03130 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03131 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table);
03132 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03133 if (!stmt) {
03134 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03135 ast_odbc_release_obj(obj);
03136 goto yuck;
03137 }
03138 res = SQLFetch(stmt);
03139 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03140 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03141 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03142 ast_odbc_release_obj(obj);
03143 goto yuck;
03144 }
03145 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03146 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03147 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03148 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03149 ast_odbc_release_obj(obj);
03150 goto yuck;
03151 }
03152 if (sscanf(rowdata, "%30d", &x) != 1)
03153 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03154 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03155 ast_odbc_release_obj(obj);
03156 } else
03157 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03158 yuck:
03159 return x;
03160 }
03161
03162
03163
03164
03165
03166
03167
03168
03169
03170
03171
03172
03173
03174 static int count_messages(struct ast_vm_user *vmu, char *dir)
03175 {
03176 return last_message_index(vmu, dir) + 1;
03177 }
03178
03179
03180
03181
03182
03183
03184
03185
03186
03187
03188
03189 static void delete_file(const char *sdir, int smsg)
03190 {
03191 SQLHSTMT stmt;
03192 char sql[PATH_MAX];
03193 char msgnums[20];
03194 char *argv[] = { NULL, msgnums };
03195 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03196 struct odbc_obj *obj;
03197
03198 argv[0] = ast_strdupa(sdir);
03199
03200 obj = ast_odbc_request_obj(odbc_database, 0);
03201 if (obj) {
03202 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03203 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table);
03204 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03205 if (!stmt)
03206 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03207 else
03208 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03209 ast_odbc_release_obj(obj);
03210 } else
03211 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03212 return;
03213 }
03214
03215
03216
03217
03218
03219
03220
03221
03222
03223
03224
03225
03226 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03227 {
03228 SQLHSTMT stmt;
03229 char sql[512];
03230 char msgnums[20];
03231 char msgnumd[20];
03232 struct odbc_obj *obj;
03233 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03234 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03235
03236 delete_file(ddir, dmsg);
03237 obj = ast_odbc_request_obj(odbc_database, 0);
03238 if (obj) {
03239 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03240 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03241 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?",odbc_table,odbc_table);
03242 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03243 if (!stmt)
03244 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03245 else
03246 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03247 ast_odbc_release_obj(obj);
03248 } else
03249 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03250 return;
03251 }
03252
03253 struct insert_data {
03254 char *sql;
03255 const char *dir;
03256 const char *msgnums;
03257 void *data;
03258 SQLLEN datalen;
03259 SQLLEN indlen;
03260 const char *context;
03261 const char *macrocontext;
03262 const char *callerid;
03263 const char *origtime;
03264 const char *duration;
03265 const char *mailboxuser;
03266 const char *mailboxcontext;
03267 const char *category;
03268 const char *flag;
03269 };
03270
03271 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03272 {
03273 struct insert_data *data = vdata;
03274 int res;
03275 SQLHSTMT stmt;
03276
03277 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03278 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03279 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03280 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03281 return NULL;
03282 }
03283
03284 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *)data->dir, 0, NULL);
03285 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *)data->msgnums, 0, NULL);
03286 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *)data->data, data->datalen, &data->indlen);
03287 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *)data->context, 0, NULL);
03288 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *)data->macrocontext, 0, NULL);
03289 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *)data->callerid, 0, NULL);
03290 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *)data->origtime, 0, NULL);
03291 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *)data->duration, 0, NULL);
03292 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *)data->mailboxuser, 0, NULL);
03293 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *)data->mailboxcontext, 0, NULL);
03294 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *)data->flag, 0, NULL);
03295 if (!ast_strlen_zero(data->category)) {
03296 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *)data->category, 0, NULL);
03297 }
03298 res = SQLExecDirect(stmt, (unsigned char *)data->sql, SQL_NTS);
03299 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03300 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03301 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03302 return NULL;
03303 }
03304
03305 return stmt;
03306 }
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03322 {
03323 int res = 0;
03324 int fd = -1;
03325 void *fdm = MAP_FAILED;
03326 size_t fdlen = -1;
03327 SQLHSTMT stmt;
03328 char sql[PATH_MAX];
03329 char msgnums[20];
03330 char fn[PATH_MAX];
03331 char full_fn[PATH_MAX];
03332 char fmt[80]="";
03333 char *c;
03334 struct ast_config *cfg=NULL;
03335 struct odbc_obj *obj;
03336 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03337 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03338 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03339
03340 delete_file(dir, msgnum);
03341 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03342 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03343 return -1;
03344 }
03345
03346 do {
03347 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03348 c = strchr(fmt, '|');
03349 if (c)
03350 *c = '\0';
03351 if (!strcasecmp(fmt, "wav49"))
03352 strcpy(fmt, "WAV");
03353 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
03354 if (msgnum > -1)
03355 make_file(fn, sizeof(fn), dir, msgnum);
03356 else
03357 ast_copy_string(fn, dir, sizeof(fn));
03358 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03359 cfg = ast_config_load(full_fn, config_flags);
03360 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03361 fd = open(full_fn, O_RDWR);
03362 if (fd < 0) {
03363 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03364 res = -1;
03365 break;
03366 }
03367 if (cfg) {
03368 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03369 idata.context = "";
03370 }
03371 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03372 idata.macrocontext = "";
03373 }
03374 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03375 idata.callerid = "";
03376 }
03377 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03378 idata.origtime = "";
03379 }
03380 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03381 idata.duration = "";
03382 }
03383 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03384 idata.category = "";
03385 }
03386 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03387 idata.flag = "";
03388 }
03389 }
03390 fdlen = lseek(fd, 0, SEEK_END);
03391 lseek(fd, 0, SEEK_SET);
03392 printf("Length is %zd\n", fdlen);
03393 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
03394 if (fdm == MAP_FAILED) {
03395 ast_log(AST_LOG_WARNING, "Memory map failed!\n");
03396 res = -1;
03397 break;
03398 }
03399 idata.data = fdm;
03400 idata.datalen = idata.indlen = fdlen;
03401
03402 if (!ast_strlen_zero(idata.category))
03403 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
03404 else
03405 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
03406
03407 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03408 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03409 } else {
03410 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03411 res = -1;
03412 }
03413 } while (0);
03414 if (obj) {
03415 ast_odbc_release_obj(obj);
03416 }
03417 if (cfg)
03418 ast_config_destroy(cfg);
03419 if (fdm != MAP_FAILED)
03420 munmap(fdm, fdlen);
03421 if (fd > -1)
03422 close(fd);
03423 return res;
03424 }
03425
03426
03427
03428
03429
03430
03431
03432
03433
03434
03435
03436
03437
03438
03439 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03440 {
03441 SQLHSTMT stmt;
03442 char sql[PATH_MAX];
03443 char msgnums[20];
03444 char msgnumd[20];
03445 struct odbc_obj *obj;
03446 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03447 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03448
03449 delete_file(ddir, dmsg);
03450 obj = ast_odbc_request_obj(odbc_database, 0);
03451 if (obj) {
03452 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03453 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03454 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table);
03455 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03456 if (!stmt)
03457 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03458 else
03459 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03460 ast_odbc_release_obj(obj);
03461 } else
03462 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03463 return;
03464 }
03465
03466
03467
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477 static int remove_file(char *dir, int msgnum)
03478 {
03479 char fn[PATH_MAX];
03480 char full_fn[PATH_MAX];
03481 char msgnums[80];
03482
03483 if (msgnum > -1) {
03484 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03485 make_file(fn, sizeof(fn), dir, msgnum);
03486 } else
03487 ast_copy_string(fn, dir, sizeof(fn));
03488 ast_filedelete(fn, NULL);
03489 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03490 unlink(full_fn);
03491 return 0;
03492 }
03493 #else
03494 #ifndef IMAP_STORAGE
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504 static int count_messages(struct ast_vm_user *vmu, char *dir)
03505 {
03506
03507 int vmcount = 0;
03508 DIR *vmdir = NULL;
03509 struct dirent *vment = NULL;
03510
03511 if (vm_lock_path(dir))
03512 return ERROR_LOCK_PATH;
03513
03514 if ((vmdir = opendir(dir))) {
03515 while ((vment = readdir(vmdir))) {
03516 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03517 vmcount++;
03518 }
03519 }
03520 closedir(vmdir);
03521 }
03522 ast_unlock_path(dir);
03523
03524 return vmcount;
03525 }
03526
03527
03528
03529
03530
03531
03532
03533
03534 static void rename_file(char *sfn, char *dfn)
03535 {
03536 char stxt[PATH_MAX];
03537 char dtxt[PATH_MAX];
03538 ast_filerename(sfn,dfn,NULL);
03539 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
03540 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
03541 if (ast_check_realtime("voicemail_data")) {
03542 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
03543 }
03544 rename(stxt, dtxt);
03545 }
03546
03547
03548
03549
03550
03551
03552
03553
03554
03555
03556
03557
03558 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03559 {
03560 int x;
03561 unsigned char map[MAXMSGLIMIT] = "";
03562 DIR *msgdir;
03563 struct dirent *msgdirent;
03564 int msgdirint;
03565
03566
03567
03568
03569
03570 if (!(msgdir = opendir(dir))) {
03571 return -1;
03572 }
03573
03574 while ((msgdirent = readdir(msgdir))) {
03575 if (sscanf(msgdirent->d_name, "msg%30d", &msgdirint) == 1 && msgdirint < MAXMSGLIMIT)
03576 map[msgdirint] = 1;
03577 }
03578 closedir(msgdir);
03579
03580 for (x = 0; x < vmu->maxmsg; x++) {
03581 if (map[x] == 0)
03582 break;
03583 }
03584
03585 return x - 1;
03586 }
03587
03588 #endif
03589 #endif
03590 #ifndef IMAP_STORAGE
03591
03592
03593
03594
03595
03596
03597
03598
03599
03600
03601 static int copy(char *infile, char *outfile)
03602 {
03603 int ifd;
03604 int ofd;
03605 int res;
03606 int len;
03607 char buf[4096];
03608
03609 #ifdef HARDLINK_WHEN_POSSIBLE
03610
03611 if (link(infile, outfile)) {
03612 #endif
03613 if ((ifd = open(infile, O_RDONLY)) < 0) {
03614 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
03615 return -1;
03616 }
03617 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
03618 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
03619 close(ifd);
03620 return -1;
03621 }
03622 do {
03623 len = read(ifd, buf, sizeof(buf));
03624 if (len < 0) {
03625 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
03626 close(ifd);
03627 close(ofd);
03628 unlink(outfile);
03629 }
03630 if (len) {
03631 res = write(ofd, buf, len);
03632 if (errno == ENOMEM || errno == ENOSPC || res != len) {
03633 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
03634 close(ifd);
03635 close(ofd);
03636 unlink(outfile);
03637 }
03638 }
03639 } while (len);
03640 close(ifd);
03641 close(ofd);
03642 return 0;
03643 #ifdef HARDLINK_WHEN_POSSIBLE
03644 } else {
03645
03646 return 0;
03647 }
03648 #endif
03649 }
03650
03651
03652
03653
03654
03655
03656
03657
03658
03659
03660 static void copy_plain_file(char *frompath, char *topath)
03661 {
03662 char frompath2[PATH_MAX], topath2[PATH_MAX];
03663 struct ast_variable *tmp,*var = NULL;
03664 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
03665 ast_filecopy(frompath, topath, NULL);
03666 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
03667 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
03668 if (ast_check_realtime("voicemail_data")) {
03669 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
03670
03671 for (tmp = var; tmp; tmp = tmp->next) {
03672 if (!strcasecmp(tmp->name, "origmailbox")) {
03673 origmailbox = tmp->value;
03674 } else if (!strcasecmp(tmp->name, "context")) {
03675 context = tmp->value;
03676 } else if (!strcasecmp(tmp->name, "macrocontext")) {
03677 macrocontext = tmp->value;
03678 } else if (!strcasecmp(tmp->name, "exten")) {
03679 exten = tmp->value;
03680 } else if (!strcasecmp(tmp->name, "priority")) {
03681 priority = tmp->value;
03682 } else if (!strcasecmp(tmp->name, "callerchan")) {
03683 callerchan = tmp->value;
03684 } else if (!strcasecmp(tmp->name, "callerid")) {
03685 callerid = tmp->value;
03686 } else if (!strcasecmp(tmp->name, "origdate")) {
03687 origdate = tmp->value;
03688 } else if (!strcasecmp(tmp->name, "origtime")) {
03689 origtime = tmp->value;
03690 } else if (!strcasecmp(tmp->name, "category")) {
03691 category = tmp->value;
03692 } else if (!strcasecmp(tmp->name, "duration")) {
03693 duration = tmp->value;
03694 }
03695 }
03696 ast_store_realtime("voicemail_data", "filename", topath, "origmailbox", origmailbox, "context", context, "macrocontext", macrocontext, "exten", exten, "priority", priority, "callerchan", callerchan, "callerid", callerid, "origdate", origdate, "origtime", origtime, "category", category, "duration", duration, SENTINEL);
03697 }
03698 copy(frompath2, topath2);
03699 ast_variables_destroy(var);
03700 }
03701 #endif
03702
03703
03704
03705
03706
03707
03708
03709
03710
03711 static int vm_delete(char *file)
03712 {
03713 char *txt;
03714 int txtsize = 0;
03715
03716 txtsize = (strlen(file) + 5)*sizeof(char);
03717 txt = alloca(txtsize);
03718
03719
03720
03721 if (ast_check_realtime("voicemail_data")) {
03722 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
03723 }
03724 snprintf(txt, txtsize, "%s.txt", file);
03725 unlink(txt);
03726 return ast_filedelete(file, NULL);
03727 }
03728
03729
03730
03731
03732 static int inbuf(struct baseio *bio, FILE *fi)
03733 {
03734 int l;
03735
03736 if (bio->ateof)
03737 return 0;
03738
03739 if ((l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
03740 if (ferror(fi))
03741 return -1;
03742
03743 bio->ateof = 1;
03744 return 0;
03745 }
03746
03747 bio->iolen= l;
03748 bio->iocp= 0;
03749
03750 return 1;
03751 }
03752
03753
03754
03755
03756 static int inchar(struct baseio *bio, FILE *fi)
03757 {
03758 if (bio->iocp>=bio->iolen) {
03759 if (!inbuf(bio, fi))
03760 return EOF;
03761 }
03762
03763 return bio->iobuf[bio->iocp++];
03764 }
03765
03766
03767
03768
03769 static int ochar(struct baseio *bio, int c, FILE *so)
03770 {
03771 if (bio->linelength >= BASELINELEN) {
03772 if (fputs(eol,so) == EOF)
03773 return -1;
03774
03775 bio->linelength= 0;
03776 }
03777
03778 if (putc(((unsigned char)c),so) == EOF)
03779 return -1;
03780
03781 bio->linelength++;
03782
03783 return 1;
03784 }
03785
03786
03787
03788
03789
03790
03791
03792
03793
03794
03795 static int base_encode(char *filename, FILE *so)
03796 {
03797 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
03798 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
03799 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
03800 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
03801 int i,hiteof= 0;
03802 FILE *fi;
03803 struct baseio bio;
03804
03805 memset(&bio, 0, sizeof(bio));
03806 bio.iocp = BASEMAXINLINE;
03807
03808 if (!(fi = fopen(filename, "rb"))) {
03809 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
03810 return -1;
03811 }
03812
03813 while (!hiteof){
03814 unsigned char igroup[3], ogroup[4];
03815 int c,n;
03816
03817 igroup[0]= igroup[1]= igroup[2]= 0;
03818
03819 for (n= 0;n<3;n++) {
03820 if ((c = inchar(&bio, fi)) == EOF) {
03821 hiteof= 1;
03822 break;
03823 }
03824
03825 igroup[n]= (unsigned char)c;
03826 }
03827
03828 if (n> 0) {
03829 ogroup[0]= dtable[igroup[0]>>2];
03830 ogroup[1]= dtable[((igroup[0]&3)<<4) | (igroup[1]>>4)];
03831 ogroup[2]= dtable[((igroup[1]&0xF)<<2) | (igroup[2]>>6)];
03832 ogroup[3]= dtable[igroup[2]&0x3F];
03833
03834 if (n<3) {
03835 ogroup[3]= '=';
03836
03837 if (n<2)
03838 ogroup[2]= '=';
03839 }
03840
03841 for (i= 0;i<4;i++)
03842 ochar(&bio, ogroup[i], so);
03843 }
03844 }
03845
03846 fclose(fi);
03847
03848 if (fputs(eol,so)==EOF)
03849 return 0;
03850
03851 return 1;
03852 }
03853
03854 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category, const char *flag)
03855 {
03856 char callerid[256];
03857 char fromdir[256], fromfile[256];
03858 struct ast_config *msg_cfg;
03859 const char *origcallerid, *origtime;
03860 char origcidname[80], origcidnum[80], origdate[80];
03861 int inttime;
03862 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03863
03864
03865 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
03866 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
03867 snprintf(passdata, passdatasize, "%d", msgnum);
03868 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
03869 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
03870 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
03871 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
03872 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
03873 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
03874 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
03875 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
03876 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
03877 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
03878
03879
03880 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
03881 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
03882 if (strlen(fromfile) < sizeof(fromfile) - 5) {
03883 strcat(fromfile, ".txt");
03884 }
03885 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
03886 if (option_debug > 0) {
03887 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
03888 }
03889 return;
03890 }
03891
03892 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
03893 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
03894 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
03895 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
03896 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
03897 }
03898
03899 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
03900 struct timeval tv = { inttime, };
03901 struct ast_tm tm;
03902 ast_localtime(&tv, &tm, NULL);
03903 ast_strftime(origdate, sizeof(origdate), emaildateformat, &tm);
03904 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
03905 }
03906 ast_config_destroy(msg_cfg);
03907 }
03908
03909
03910
03911
03912
03913
03914
03915
03916 static char *quote(const char *from, char *to, size_t len)
03917 {
03918 char *ptr = to;
03919 *ptr++ = '"';
03920 for (; ptr < to + len - 1; from++) {
03921 if (*from == '"')
03922 *ptr++ = '\\';
03923 else if (*from == '\0')
03924 break;
03925 *ptr++ = *from;
03926 }
03927 if (ptr < to + len - 1)
03928 *ptr++ = '"';
03929 *ptr = '\0';
03930 return to;
03931 }
03932
03933
03934
03935
03936
03937 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
03938 {
03939 const struct vm_zone *z = NULL;
03940 struct timeval t = ast_tvnow();
03941
03942
03943 if (!ast_strlen_zero(vmu->zonetag)) {
03944
03945 AST_LIST_LOCK(&zones);
03946 AST_LIST_TRAVERSE(&zones, z, list) {
03947 if (!strcmp(z->name, vmu->zonetag))
03948 break;
03949 }
03950 AST_LIST_UNLOCK(&zones);
03951 }
03952 ast_localtime(&t, tm, z ? z->timezone : NULL);
03953 return tm;
03954 }
03955
03956
03957
03958
03959
03960 static int check_mime(const char *str)
03961 {
03962 for (; *str; str++) {
03963 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
03964 return 1;
03965 }
03966 }
03967 return 0;
03968 }
03969
03970
03971
03972
03973
03974
03975
03976
03977
03978
03979
03980
03981
03982
03983
03984
03985
03986 static char *encode_mime_str(const char *start, char *end, size_t endsize, size_t preamble, size_t postamble)
03987 {
03988 char tmp[80];
03989 int first_section = 1;
03990 size_t endlen = 0, tmplen = 0;
03991 *end = '\0';
03992
03993 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
03994 for (; *start; start++) {
03995 int need_encoding = 0;
03996 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
03997 need_encoding = 1;
03998 }
03999 if ((first_section && need_encoding && preamble + tmplen > 70) ||
04000 (first_section && !need_encoding && preamble + tmplen > 72) ||
04001 (!first_section && need_encoding && tmplen > 70) ||
04002 (!first_section && !need_encoding && tmplen > 72)) {
04003
04004 endlen += snprintf(end + endlen, endsize - endlen, "%s%s?=", first_section ? "" : " ", tmp);
04005 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
04006 first_section = 0;
04007 }
04008 if (need_encoding && *start == ' ') {
04009 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "_");
04010 } else if (need_encoding) {
04011 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "=%hhX", *start);
04012 } else {
04013 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%c", *start);
04014 }
04015 }
04016 snprintf(end + endlen, endsize - endlen, "%s%s?=%s", first_section ? "" : " ", tmp, endlen + postamble > 74 ? " " : "");
04017 return end;
04018 }
04019
04020
04021
04022
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037
04038
04039
04040 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag)
04041 {
04042 char date[256];
04043 char host[MAXHOSTNAMELEN] = "";
04044 char who[256];
04045 char bound[256];
04046 char dur[256];
04047 struct ast_tm tm;
04048 char enc_cidnum[256] = "", enc_cidname[256] = "";
04049 char *passdata = NULL, *passdata2;
04050 size_t len_passdata = 0, len_passdata2, tmplen;
04051 char *greeting_attachment;
04052 char filename[256];
04053
04054 #ifdef IMAP_STORAGE
04055 #define ENDL "\r\n"
04056 #else
04057 #define ENDL "\n"
04058 #endif
04059
04060
04061 len_passdata2 = strlen(vmu->fullname);
04062 if (emailsubject && (tmplen = strlen(emailsubject)) > len_passdata2) {
04063 len_passdata2 = tmplen;
04064 }
04065 if ((tmplen = strlen(fromstring)) > len_passdata2) {
04066 len_passdata2 = tmplen;
04067 }
04068 len_passdata2 = len_passdata2 * 3 + 200;
04069 passdata2 = alloca(len_passdata2);
04070
04071 if (cidnum) {
04072 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04073 }
04074 if (cidname) {
04075 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04076 }
04077 gethostname(host, sizeof(host) - 1);
04078
04079 if (strchr(srcemail, '@'))
04080 ast_copy_string(who, srcemail, sizeof(who));
04081 else
04082 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04083
04084 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04085 if (greeting_attachment)
04086 *greeting_attachment++ = '\0';
04087
04088 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04089 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04090 fprintf(p, "Date: %s" ENDL, date);
04091
04092
04093 ast_strftime(date, sizeof(date), emaildateformat, &tm);
04094
04095 if (!ast_strlen_zero(fromstring)) {
04096 struct ast_channel *ast;
04097 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04098 char *ptr;
04099 memset(passdata2, 0, len_passdata2);
04100 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category, flag);
04101 pbx_substitute_variables_helper(ast, fromstring, passdata2, len_passdata2);
04102 len_passdata = strlen(passdata2) * 3 + 300;
04103 passdata = alloca(len_passdata);
04104 if (check_mime(passdata2)) {
04105 int first_line = 1;
04106 encode_mime_str(passdata2, passdata, len_passdata, strlen("From: "), strlen(who) + 3);
04107 while ((ptr = strchr(passdata, ' '))) {
04108 *ptr = '\0';
04109 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", passdata);
04110 first_line = 0;
04111 passdata = ptr + 1;
04112 }
04113 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", passdata, who);
04114 } else {
04115 fprintf(p, "From: %s <%s>" ENDL, quote(passdata2, passdata, len_passdata), who);
04116 }
04117 ast_channel_free(ast);
04118 } else {
04119 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04120 }
04121 } else {
04122 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04123 }
04124
04125 if (check_mime(vmu->fullname)) {
04126 int first_line = 1;
04127 char *ptr;
04128 encode_mime_str(vmu->fullname, passdata2, len_passdata2, strlen("To: "), strlen(vmu->email) + 3);
04129 while ((ptr = strchr(passdata2, ' '))) {
04130 *ptr = '\0';
04131 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", passdata2);
04132 first_line = 0;
04133 passdata2 = ptr + 1;
04134 }
04135 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", passdata2, vmu->email);
04136 } else {
04137 fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata2), vmu->email);
04138 }
04139 if (!ast_strlen_zero(emailsubject)) {
04140 struct ast_channel *ast;
04141 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04142 int vmlen = strlen(emailsubject) * 3 + 200;
04143
04144 if (vmlen > len_passdata) {
04145 passdata = alloca(vmlen);
04146 len_passdata = vmlen;
04147 }
04148
04149 memset(passdata, 0, len_passdata);
04150 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, len_passdata, category, flag);
04151 pbx_substitute_variables_helper(ast, emailsubject, passdata, len_passdata);
04152 if (check_mime(passdata)) {
04153 int first_line = 1;
04154 char *ptr;
04155 encode_mime_str(passdata, passdata2, len_passdata2, strlen("Subject: "), 0);
04156 while ((ptr = strchr(passdata2, ' '))) {
04157 *ptr = '\0';
04158 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
04159 first_line = 0;
04160 passdata2 = ptr + 1;
04161 }
04162 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
04163 } else {
04164 fprintf(p, "Subject: %s" ENDL, passdata);
04165 }
04166 ast_channel_free(ast);
04167 } else {
04168 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04169 }
04170 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04171 if (ast_strlen_zero(flag)) {
04172 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04173 } else {
04174 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04175 }
04176 } else {
04177 if (ast_strlen_zero(flag)) {
04178 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04179 } else {
04180 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04181 }
04182 }
04183
04184 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1, (unsigned int)ast_random(), mailbox, (int)getpid(), host);
04185 if (imap) {
04186
04187 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04188
04189 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04190 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04191 #ifdef IMAP_STORAGE
04192 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04193 #else
04194 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04195 #endif
04196
04197 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04198 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04199 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04200 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04201 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04202 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04203 if (!ast_strlen_zero(category)) {
04204 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04205 } else {
04206 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04207 }
04208 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04209 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04210 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long)time(NULL));
04211 }
04212 if (!ast_strlen_zero(cidnum)) {
04213 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04214 }
04215 if (!ast_strlen_zero(cidname)) {
04216 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04217 }
04218 fprintf(p, "MIME-Version: 1.0" ENDL);
04219 if (attach_user_voicemail) {
04220
04221 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox, (int)getpid(), (unsigned int)ast_random());
04222
04223 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04224 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04225 fprintf(p, "--%s" ENDL, bound);
04226 }
04227 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04228 if (emailbody) {
04229 struct ast_channel *ast;
04230 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04231 char *passdata;
04232 int vmlen = strlen(emailbody)*3 + 200;
04233 passdata = alloca(vmlen);
04234 memset(passdata, 0, vmlen);
04235 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04236 pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
04237 fprintf(p, "%s" ENDL, passdata);
04238 ast_channel_free(ast);
04239 } else
04240 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04241 } else if (msgnum > -1) {
04242 if (strcmp(vmu->mailbox, mailbox)) {
04243
04244 struct ast_config *msg_cfg;
04245 const char *v;
04246 int inttime;
04247 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04248 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04249
04250 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04251 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04252 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04253 strcat(fromfile, ".txt");
04254 }
04255 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04256 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04257 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04258 }
04259
04260
04261
04262 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04263 struct timeval tv = { inttime, };
04264 struct ast_tm tm;
04265 ast_localtime(&tv, &tm, NULL);
04266 ast_strftime(origdate, sizeof(origdate), emaildateformat, &tm);
04267 }
04268 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04269 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04270 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04271 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04272 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04273 date, origcallerid, origdate);
04274 ast_config_destroy(msg_cfg);
04275 } else {
04276 goto plain_message;
04277 }
04278 } else {
04279 plain_message:
04280 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04281 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04282 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04283 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04284 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04285 }
04286 } else {
04287 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04288 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04289 }
04290
04291 if (imap || attach_user_voicemail) {
04292 if (!ast_strlen_zero(attach2)) {
04293 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04294 ast_debug(5, "creating second attachment filename %s\n", filename);
04295 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04296 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04297 ast_debug(5, "creating attachment filename %s\n", filename);
04298 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04299 } else {
04300 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04301 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04302 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04303 }
04304 }
04305 }
04306
04307 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum)
04308 {
04309 char tmpdir[256], newtmp[256];
04310 char fname[256];
04311 char tmpcmd[256];
04312 int tmpfd = -1;
04313
04314
04315 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04316
04317 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04318 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04319 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04320 tmpfd = mkstemp(newtmp);
04321 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04322 ast_debug(3, "newtmp: %s\n", newtmp);
04323 if (tmpfd > -1) {
04324 int soxstatus;
04325 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04326 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04327 attach = newtmp;
04328 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04329 } else {
04330 ast_log(LOG_WARNING, "Sox failed to reencode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04331 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04332 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04333 }
04334 }
04335 }
04336 fprintf(p, "--%s" ENDL, bound);
04337 if (msgnum > -1)
04338 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04339 else
04340 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04341 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04342 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04343 if (msgnum > -1)
04344 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04345 else
04346 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04347 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04348 base_encode(fname, p);
04349 if (last)
04350 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04351 if (tmpfd > -1) {
04352 unlink(fname);
04353 close(tmpfd);
04354 unlink(newtmp);
04355 }
04356 return 0;
04357 }
04358 #undef ENDL
04359
04360 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag)
04361 {
04362 FILE *p=NULL;
04363 char tmp[80] = "/tmp/astmail-XXXXXX";
04364 char tmp2[256];
04365
04366 if (vmu && ast_strlen_zero(vmu->email)) {
04367 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04368 return(0);
04369 }
04370 if (!strcmp(format, "wav49"))
04371 format = "WAV";
04372 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04373
04374
04375 if ((p = vm_mkftemp(tmp)) == NULL) {
04376 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04377 return -1;
04378 } else {
04379 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04380 fclose(p);
04381 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04382 ast_safe_system(tmp2);
04383 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04384 }
04385 return 0;
04386 }
04387
04388 static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
04389 {
04390 char date[256];
04391 char host[MAXHOSTNAMELEN] = "";
04392 char who[256];
04393 char dur[PATH_MAX];
04394 char tmp[80] = "/tmp/astmail-XXXXXX";
04395 char tmp2[PATH_MAX];
04396 struct ast_tm tm;
04397 FILE *p;
04398
04399 if ((p = vm_mkftemp(tmp)) == NULL) {
04400 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04401 return -1;
04402 }
04403 gethostname(host, sizeof(host)-1);
04404 if (strchr(srcemail, '@'))
04405 ast_copy_string(who, srcemail, sizeof(who));
04406 else
04407 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04408 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04409 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04410 fprintf(p, "Date: %s\n", date);
04411
04412 if (*pagerfromstring) {
04413 struct ast_channel *ast;
04414 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04415 char *passdata;
04416 int vmlen = strlen(fromstring)*3 + 200;
04417 passdata = alloca(vmlen);
04418 memset(passdata, 0, vmlen);
04419 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04420 pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
04421 fprintf(p, "From: %s <%s>\n", passdata, who);
04422 ast_channel_free(ast);
04423 } else
04424 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04425 } else
04426 fprintf(p, "From: Asterisk PBX <%s>\n", who);
04427 fprintf(p, "To: %s\n", pager);
04428 if (pagersubject) {
04429 struct ast_channel *ast;
04430 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04431 char *passdata;
04432 int vmlen = strlen(pagersubject) * 3 + 200;
04433 passdata = alloca(vmlen);
04434 memset(passdata, 0, vmlen);
04435 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04436 pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
04437 fprintf(p, "Subject: %s\n\n", passdata);
04438 ast_channel_free(ast);
04439 } else
04440 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04441 } else {
04442 if (ast_strlen_zero(flag)) {
04443 fprintf(p, "Subject: New VM\n\n");
04444 } else {
04445 fprintf(p, "Subject: New %s VM\n\n", flag);
04446 }
04447 }
04448
04449 ast_strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
04450 if (pagerbody) {
04451 struct ast_channel *ast;
04452 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04453 char *passdata;
04454 int vmlen = strlen(pagerbody) * 3 + 200;
04455 passdata = alloca(vmlen);
04456 memset(passdata, 0, vmlen);
04457 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04458 pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
04459 fprintf(p, "%s\n", passdata);
04460 ast_channel_free(ast);
04461 } else
04462 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04463 } else {
04464 fprintf(p, "New %s long %s msg in box %s\n"
04465 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
04466 }
04467 fclose(p);
04468 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04469 ast_safe_system(tmp2);
04470 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
04471 return 0;
04472 }
04473
04474
04475
04476
04477
04478
04479
04480
04481
04482
04483 static int get_date(char *s, int len)
04484 {
04485 struct ast_tm tm;
04486 struct timeval t = ast_tvnow();
04487
04488 ast_localtime(&t, &tm, "UTC");
04489
04490 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
04491 }
04492
04493 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
04494 {
04495 int res;
04496 char fn[PATH_MAX];
04497 char dest[PATH_MAX];
04498
04499 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
04500
04501 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
04502 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
04503 return -1;
04504 }
04505
04506 RETRIEVE(fn, -1, ext, context);
04507 if (ast_fileexists(fn, NULL, NULL) > 0) {
04508 res = ast_stream_and_wait(chan, fn, ecodes);
04509 if (res) {
04510 DISPOSE(fn, -1);
04511 return res;
04512 }
04513 } else {
04514
04515 DISPOSE(fn, -1);
04516 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
04517 if (res)
04518 return res;
04519 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
04520 if (res)
04521 return res;
04522 }
04523 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
04524 return res;
04525 }
04526
04527 static void free_zone(struct vm_zone *z)
04528 {
04529 ast_free(z);
04530 }
04531
04532 #ifdef ODBC_STORAGE
04533 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
04534 {
04535 int x = -1;
04536 int res;
04537 SQLHSTMT stmt = NULL;
04538 char sql[PATH_MAX];
04539 char rowdata[20];
04540 char tmp[PATH_MAX] = "";
04541 struct odbc_obj *obj = NULL;
04542 char *context;
04543 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04544
04545 if (newmsgs)
04546 *newmsgs = 0;
04547 if (oldmsgs)
04548 *oldmsgs = 0;
04549 if (urgentmsgs)
04550 *urgentmsgs = 0;
04551
04552
04553 if (ast_strlen_zero(mailbox))
04554 return 0;
04555
04556 ast_copy_string(tmp, mailbox, sizeof(tmp));
04557
04558 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
04559 int u, n, o;
04560 char *next, *remaining = tmp;
04561 while ((next = strsep(&remaining, " ,"))) {
04562 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
04563 return -1;
04564 }
04565 if (urgentmsgs) {
04566 *urgentmsgs += u;
04567 }
04568 if (newmsgs) {
04569 *newmsgs += n;
04570 }
04571 if (oldmsgs) {
04572 *oldmsgs += o;
04573 }
04574 }
04575 return 0;
04576 }
04577
04578 context = strchr(tmp, '@');
04579 if (context) {
04580 *context = '\0';
04581 context++;
04582 } else
04583 context = "default";
04584
04585 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
04586 do {
04587 if (newmsgs) {
04588 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
04589 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
04590 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04591 break;
04592 }
04593 res = SQLFetch(stmt);
04594 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04595 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04596 break;
04597 }
04598 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04599 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04600 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04601 break;
04602 }
04603 *newmsgs = atoi(rowdata);
04604 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04605 }
04606
04607 if (oldmsgs) {
04608 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
04609 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
04610 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04611 break;
04612 }
04613 res = SQLFetch(stmt);
04614 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04615 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04616 break;
04617 }
04618 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04619 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04620 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04621 break;
04622 }
04623 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
04624 *oldmsgs = atoi(rowdata);
04625 }
04626
04627 if (urgentmsgs) {
04628 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
04629 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
04630 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04631 break;
04632 }
04633 res = SQLFetch(stmt);
04634 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04635 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04636 break;
04637 }
04638 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04639 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04640 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04641 break;
04642 }
04643 *urgentmsgs = atoi(rowdata);
04644 }
04645
04646 x = 0;
04647 } while (0);
04648 } else {
04649 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04650 }
04651
04652 if (stmt) {
04653 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04654 }
04655 if (obj) {
04656 ast_odbc_release_obj(obj);
04657 }
04658
04659 return x;
04660 }
04661
04662
04663
04664
04665
04666
04667
04668
04669
04670
04671 static int messagecount(const char *context, const char *mailbox, const char *folder)
04672 {
04673 struct odbc_obj *obj = NULL;
04674 int nummsgs = 0;
04675 int res;
04676 SQLHSTMT stmt = NULL;
04677 char sql[PATH_MAX];
04678 char rowdata[20];
04679 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04680 if (!folder)
04681 folder = "INBOX";
04682
04683 if (ast_strlen_zero(mailbox))
04684 return 0;
04685
04686 obj = ast_odbc_request_obj(odbc_database, 0);
04687 if (obj) {
04688 if (!strcmp(folder, "INBOX")) {
04689 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox);
04690 } else {
04691 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
04692 }
04693 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04694 if (!stmt) {
04695 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04696 goto yuck;
04697 }
04698 res = SQLFetch(stmt);
04699 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04700 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04701 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04702 goto yuck;
04703 }
04704 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04705 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04706 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04707 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04708 goto yuck;
04709 }
04710 nummsgs = atoi(rowdata);
04711 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04712 } else
04713 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04714
04715 yuck:
04716 if (obj)
04717 ast_odbc_release_obj(obj);
04718 return nummsgs;
04719 }
04720
04721
04722
04723
04724
04725
04726
04727
04728
04729 static int has_voicemail(const char *mailbox, const char *folder)
04730 {
04731 char tmp[256], *tmp2 = tmp, *box, *context;
04732 ast_copy_string(tmp, mailbox, sizeof(tmp));
04733 while ((context = box = strsep(&tmp2, ",&"))) {
04734 strsep(&context, "@");
04735 if (ast_strlen_zero(context))
04736 context = "default";
04737 if (messagecount(context, box, folder))
04738 return 1;
04739 }
04740 return 0;
04741 }
04742 #endif
04743 #ifndef IMAP_STORAGE
04744
04745
04746
04747
04748
04749
04750
04751
04752
04753
04754
04755
04756
04757
04758
04759 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, const char *flag)
04760 {
04761 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
04762 const char *frombox = mbox(imbox);
04763 int recipmsgnum;
04764
04765 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
04766
04767 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
04768 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "Urgent");
04769 } else {
04770 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04771 }
04772
04773 if (!dir)
04774 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
04775 else
04776 ast_copy_string(fromdir, dir, sizeof(fromdir));
04777
04778 make_file(frompath, sizeof(frompath), fromdir, msgnum);
04779 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04780
04781 if (vm_lock_path(todir))
04782 return ERROR_LOCK_PATH;
04783
04784 recipmsgnum = last_message_index(recip, todir) + 1;
04785 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
04786 make_file(topath, sizeof(topath), todir, recipmsgnum);
04787 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
04788 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
04789 } else {
04790
04791
04792
04793
04794
04795 copy_plain_file(frompath, topath);
04796 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
04797 vm_delete(topath);
04798 }
04799 } else {
04800 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
04801 }
04802 ast_unlock_path(todir);
04803 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
04804
04805 return 0;
04806 }
04807 #endif
04808 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
04809
04810 static int messagecount(const char *context, const char *mailbox, const char *folder)
04811 {
04812 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
04813 }
04814
04815 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
04816 {
04817 DIR *dir;
04818 struct dirent *de;
04819 char fn[256];
04820 int ret = 0;
04821
04822
04823 if (ast_strlen_zero(mailbox))
04824 return 0;
04825
04826 if (ast_strlen_zero(folder))
04827 folder = "INBOX";
04828 if (ast_strlen_zero(context))
04829 context = "default";
04830
04831 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
04832
04833 if (!(dir = opendir(fn)))
04834 return 0;
04835
04836 while ((de = readdir(dir))) {
04837 if (!strncasecmp(de->d_name, "msg", 3)) {
04838 if (shortcircuit) {
04839 ret = 1;
04840 break;
04841 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
04842 ret++;
04843 }
04844 }
04845 }
04846
04847 closedir(dir);
04848
04849 return ret;
04850 }
04851
04852
04853
04854
04855
04856
04857
04858
04859
04860
04861 static int has_voicemail(const char *mailbox, const char *folder)
04862 {
04863 char tmp[256], *tmp2 = tmp, *box, *context;
04864 ast_copy_string(tmp, mailbox, sizeof(tmp));
04865 if (ast_strlen_zero(folder)) {
04866 folder = "INBOX";
04867 }
04868 while ((box = strsep(&tmp2, ",&"))) {
04869 if ((context = strchr(box, '@')))
04870 *context++ = '\0';
04871 else
04872 context = "default";
04873 if (__has_voicemail(context, box, folder, 1))
04874 return 1;
04875
04876 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
04877 return 1;
04878 }
04879 }
04880 return 0;
04881 }
04882
04883
04884 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
04885 {
04886 char tmp[256];
04887 char *context;
04888
04889
04890 if (ast_strlen_zero(mailbox))
04891 return 0;
04892
04893 if (newmsgs)
04894 *newmsgs = 0;
04895 if (oldmsgs)
04896 *oldmsgs = 0;
04897 if (urgentmsgs)
04898 *urgentmsgs = 0;
04899
04900 if (strchr(mailbox, ',')) {
04901 int tmpnew, tmpold, tmpurgent;
04902 char *mb, *cur;
04903
04904 ast_copy_string(tmp, mailbox, sizeof(tmp));
04905 mb = tmp;
04906 while ((cur = strsep(&mb, ", "))) {
04907 if (!ast_strlen_zero(cur)) {
04908 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
04909 return -1;
04910 else {
04911 if (newmsgs)
04912 *newmsgs += tmpnew;
04913 if (oldmsgs)
04914 *oldmsgs += tmpold;
04915 if (urgentmsgs)
04916 *urgentmsgs += tmpurgent;
04917 }
04918 }
04919 }
04920 return 0;
04921 }
04922
04923 ast_copy_string(tmp, mailbox, sizeof(tmp));
04924
04925 if ((context = strchr(tmp, '@')))
04926 *context++ = '\0';
04927 else
04928 context = "default";
04929
04930 if (newmsgs)
04931 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
04932 if (oldmsgs)
04933 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
04934 if (urgentmsgs)
04935 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
04936
04937 return 0;
04938 }
04939
04940 #endif
04941
04942
04943 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
04944 {
04945 int urgentmsgs = 0;
04946 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
04947 if (newmsgs) {
04948 *newmsgs += urgentmsgs;
04949 }
04950 return res;
04951 }
04952
04953 static void run_externnotify(char *context, char *extension, const char *flag)
04954 {
04955 char arguments[255];
04956 char ext_context[256] = "";
04957 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
04958 struct ast_smdi_mwi_message *mwi_msg;
04959
04960 if (!ast_strlen_zero(context))
04961 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
04962 else
04963 ast_copy_string(ext_context, extension, sizeof(ext_context));
04964
04965 if (smdi_iface) {
04966 if (ast_app_has_voicemail(ext_context, NULL))
04967 ast_smdi_mwi_set(smdi_iface, extension);
04968 else
04969 ast_smdi_mwi_unset(smdi_iface, extension);
04970
04971 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
04972 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
04973 if (!strncmp(mwi_msg->cause, "INV", 3))
04974 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
04975 else if (!strncmp(mwi_msg->cause, "BLK", 3))
04976 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
04977 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
04978 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
04979 } else {
04980 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
04981 }
04982 }
04983
04984 if (!ast_strlen_zero(externnotify)) {
04985 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
04986 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
04987 } else {
04988 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
04989 ast_debug(1, "Executing %s\n", arguments);
04990 ast_safe_system(arguments);
04991 }
04992 }
04993 }
04994
04995
04996
04997
04998
04999
05000 struct leave_vm_options {
05001 unsigned int flags;
05002 signed char record_gain;
05003 char *exitcontext;
05004 };
05005
05006
05007
05008
05009
05010
05011
05012
05013
05014
05015
05016 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05017 {
05018 #ifdef IMAP_STORAGE
05019 int newmsgs, oldmsgs;
05020 #else
05021 char urgdir[PATH_MAX];
05022 #endif
05023 char txtfile[PATH_MAX];
05024 char tmptxtfile[PATH_MAX];
05025 struct vm_state *vms = NULL;
05026 char callerid[256];
05027 FILE *txt;
05028 char date[256];
05029 int txtdes;
05030 int res = 0;
05031 int msgnum;
05032 int duration = 0;
05033 int ausemacro = 0;
05034 int ousemacro = 0;
05035 int ouseexten = 0;
05036 int rtmsgid = 0;
05037 char tmpid[16];
05038 char tmpdur[16];
05039 char priority[16];
05040 char origtime[16];
05041 char dir[PATH_MAX];
05042 char tmpdir[PATH_MAX];
05043 char fn[PATH_MAX];
05044 char prefile[PATH_MAX] = "";
05045 char tempfile[PATH_MAX] = "";
05046 char ext_context[256] = "";
05047 char fmt[80];
05048 char *context;
05049 char ecodes[17] = "#";
05050 struct ast_str *tmp = ast_str_create(16);
05051 char *tmpptr;
05052 struct ast_vm_user *vmu;
05053 struct ast_vm_user svm;
05054 const char *category = NULL;
05055 const char *code;
05056 const char *alldtmf = "0123456789ABCD*#";
05057 char flag[80];
05058
05059 ast_str_set(&tmp, 0, "%s", ext);
05060 ext = ast_str_buffer(tmp);
05061 if ((context = strchr(ext, '@'))) {
05062 *context++ = '\0';
05063 tmpptr = strchr(context, '&');
05064 } else {
05065 tmpptr = strchr(ext, '&');
05066 }
05067
05068 if (tmpptr)
05069 *tmpptr++ = '\0';
05070
05071 ast_channel_lock(chan);
05072 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05073 category = ast_strdupa(category);
05074 }
05075 ast_channel_unlock(chan);
05076
05077 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05078 ast_copy_string(flag, "Urgent", sizeof(flag));
05079 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05080 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05081 } else {
05082 flag[0] = '\0';
05083 }
05084
05085 ast_debug(3, "Before find_user\n");
05086 if (!(vmu = find_user(&svm, context, ext))) {
05087 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05088 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05089 ast_free(tmp);
05090 return res;
05091 }
05092
05093 if (strcmp(vmu->context, "default"))
05094 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05095 else
05096 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05097
05098
05099
05100
05101
05102
05103 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05104 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05105 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05106 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05107 }
05108
05109
05110
05111
05112 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05113 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05114 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05115 ast_free(tmp);
05116 return -1;
05117 }
05118 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05119 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05120 ast_copy_string(prefile, tempfile, sizeof(prefile));
05121
05122 DISPOSE(tempfile, -1);
05123
05124 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05125
05126
05127 if (ast_test_flag(vmu, VM_OPERATOR)) {
05128 if (!ast_strlen_zero(vmu->exit)) {
05129 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
05130 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05131 ouseexten = 1;
05132 }
05133 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
05134 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05135 ouseexten = 1;
05136 } else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
05137 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05138 ousemacro = 1;
05139 }
05140 }
05141
05142 if (!ast_strlen_zero(vmu->exit)) {
05143 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
05144 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05145 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
05146 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05147 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
05148 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05149 ausemacro = 1;
05150 }
05151
05152 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05153 for (code = alldtmf; *code; code++) {
05154 char e[2] = "";
05155 e[0] = *code;
05156 if (strchr(ecodes, e[0]) == NULL && ast_canmatch_extension(chan, chan->context, e, 1, chan->cid.cid_num))
05157 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05158 }
05159 }
05160
05161
05162 if (!ast_strlen_zero(prefile)) {
05163 #ifdef ODBC_STORAGE
05164 int success =
05165 #endif
05166 RETRIEVE(prefile, -1, ext, context);
05167 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05168 if (ast_streamfile(chan, prefile, chan->language) > -1)
05169 res = ast_waitstream(chan, ecodes);
05170 #ifdef ODBC_STORAGE
05171 if (success == -1) {
05172
05173 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05174 store_file(prefile, vmu->mailbox, vmu->context, -1);
05175 }
05176 #endif
05177 } else {
05178 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05179 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05180 }
05181 DISPOSE(prefile, -1);
05182 if (res < 0) {
05183 ast_debug(1, "Hang up during prefile playback\n");
05184 free_user(vmu);
05185 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05186 ast_free(tmp);
05187 return -1;
05188 }
05189 }
05190 if (res == '#') {
05191
05192 ast_set_flag(options, OPT_SILENT);
05193 res = 0;
05194 }
05195 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05196 res = ast_stream_and_wait(chan, INTRO, ecodes);
05197 if (res == '#') {
05198 ast_set_flag(options, OPT_SILENT);
05199 res = 0;
05200 }
05201 }
05202 if (res > 0)
05203 ast_stopstream(chan);
05204
05205
05206 if (res == '*') {
05207 chan->exten[0] = 'a';
05208 chan->exten[1] = '\0';
05209 if (!ast_strlen_zero(vmu->exit)) {
05210 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05211 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05212 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05213 }
05214 chan->priority = 0;
05215 free_user(vmu);
05216 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05217 ast_free(tmp);
05218 return 0;
05219 }
05220
05221
05222 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05223 transfer:
05224 if (ouseexten || ousemacro) {
05225 chan->exten[0] = 'o';
05226 chan->exten[1] = '\0';
05227 if (!ast_strlen_zero(vmu->exit)) {
05228 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05229 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05230 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05231 }
05232 ast_play_and_wait(chan, "transfer");
05233 chan->priority = 0;
05234 free_user(vmu);
05235 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05236 }
05237 ast_free(tmp);
05238 return 0;
05239 }
05240
05241
05242 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05243 if (!ast_strlen_zero(options->exitcontext))
05244 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05245 free_user(vmu);
05246 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05247 ast_free(tmp);
05248 return res;
05249 }
05250
05251 if (res < 0) {
05252 free_user(vmu);
05253 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05254 ast_free(tmp);
05255 return -1;
05256 }
05257
05258 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05259 if (!ast_strlen_zero(fmt)) {
05260 msgnum = 0;
05261
05262 #ifdef IMAP_STORAGE
05263
05264
05265 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05266 if (res < 0) {
05267 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05268 ast_free(tmp);
05269 return -1;
05270 }
05271 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05272
05273
05274
05275
05276 if (!(vms = create_vm_state_from_user(vmu))) {
05277 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05278 ast_free(tmp);
05279 return -1;
05280 }
05281 }
05282 vms->newmessages++;
05283
05284
05285 msgnum = newmsgs + oldmsgs;
05286 ast_debug(3, "Messagecount set to %d\n",msgnum);
05287 snprintf(fn, sizeof(fn), "%s/imap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05288
05289 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05290
05291
05292 check_quota(vms, imapfolder);
05293 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
05294 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
05295 ast_play_and_wait(chan, "vm-mailboxfull");
05296 ast_free(tmp);
05297 return -1;
05298 }
05299
05300
05301 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, 0)) {
05302 ast_log(AST_LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u > %u)\n", msgnum, vmu->maxmsg);
05303 ast_play_and_wait(chan, "vm-mailboxfull");
05304 ast_free(tmp);
05305 return -1;
05306 }
05307 #else
05308 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05309 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05310 if (!res)
05311 res = ast_waitstream(chan, "");
05312 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05313 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05314 inprocess_count(vmu->mailbox, vmu->context, -1);
05315 goto leave_vm_out;
05316 }
05317
05318 #endif
05319 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05320 txtdes = mkstemp(tmptxtfile);
05321 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05322 if (txtdes < 0) {
05323 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05324 if (!res)
05325 res = ast_waitstream(chan, "");
05326 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05327 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05328 inprocess_count(vmu->mailbox, vmu->context, -1);
05329 goto leave_vm_out;
05330 }
05331
05332
05333 if (res >= 0) {
05334
05335 res = ast_stream_and_wait(chan, "beep", "");
05336 }
05337
05338
05339 if (ast_check_realtime("voicemail_data")) {
05340 snprintf(priority, sizeof(priority), "%d", chan->priority);
05341 snprintf(origtime, sizeof(origtime), "%ld", (long)time(NULL));
05342 get_date(date, sizeof(date));
05343 rtmsgid = ast_store_realtime("voicemail_data", "origmailbox", ext, "context", chan->context, "macrocontext", chan->macrocontext, "exten", chan->exten, "priority", priority, "callerchan", chan->name, "callerid", ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), "origdate", date, "origtime", origtime, "category", S_OR(category,""), SENTINEL);
05344 }
05345
05346
05347 txt = fdopen(txtdes, "w+");
05348 if (txt) {
05349 get_date(date, sizeof(date));
05350 fprintf(txt,
05351 ";\n"
05352 "; Message Information file\n"
05353 ";\n"
05354 "[message]\n"
05355 "origmailbox=%s\n"
05356 "context=%s\n"
05357 "macrocontext=%s\n"
05358 "exten=%s\n"
05359 "priority=%d\n"
05360 "callerchan=%s\n"
05361 "callerid=%s\n"
05362 "origdate=%s\n"
05363 "origtime=%ld\n"
05364 "category=%s\n",
05365 ext,
05366 chan->context,
05367 chan->macrocontext,
05368 chan->exten,
05369 chan->priority,
05370 chan->name,
05371 ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"),
05372 date, (long)time(NULL),
05373 category ? category : "");
05374 } else {
05375 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05376 inprocess_count(vmu->mailbox, vmu->context, -1);
05377 if (ast_check_realtime("voicemail_data")) {
05378 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05379 }
05380 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05381 goto leave_vm_out;
05382 }
05383 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms, flag);
05384
05385 if (txt) {
05386 fprintf(txt, "flag=%s\n", flag);
05387 if (duration < vmminsecs) {
05388 fclose(txt);
05389 if (option_verbose > 2)
05390 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminsecs);
05391 ast_filedelete(tmptxtfile, NULL);
05392 unlink(tmptxtfile);
05393 if (ast_check_realtime("voicemail_data")) {
05394 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
05395 ast_destroy_realtime("voicemail_data", "id", tmpid, SENTINEL);
05396 }
05397 inprocess_count(vmu->mailbox, vmu->context, -1);
05398 } else {
05399 fprintf(txt, "duration=%d\n", duration);
05400 fclose(txt);
05401 if (vm_lock_path(dir)) {
05402 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05403
05404 ast_filedelete(tmptxtfile, NULL);
05405 unlink(tmptxtfile);
05406 inprocess_count(vmu->mailbox, vmu->context, -1);
05407 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
05408 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
05409 unlink(tmptxtfile);
05410 ast_unlock_path(dir);
05411 inprocess_count(vmu->mailbox, vmu->context, -1);
05412 if (ast_check_realtime("voicemail_data")) {
05413 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
05414 ast_destroy_realtime("voicemail_data", "id", tmpid, SENTINEL);
05415 }
05416 } else {
05417 #ifndef IMAP_STORAGE
05418 msgnum = last_message_index(vmu, dir) + 1;
05419 #endif
05420 make_file(fn, sizeof(fn), dir, msgnum);
05421
05422
05423 #ifndef IMAP_STORAGE
05424 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
05425 #else
05426 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05427 #endif
05428
05429 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
05430 ast_filerename(tmptxtfile, fn, NULL);
05431 rename(tmptxtfile, txtfile);
05432 inprocess_count(vmu->mailbox, vmu->context, -1);
05433
05434
05435
05436 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
05437 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
05438
05439 ast_unlock_path(dir);
05440 if (ast_check_realtime("voicemail_data")) {
05441 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
05442 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
05443 ast_update_realtime("voicemail_data", "id", tmpid, "filename", fn, "duration", tmpdur, SENTINEL);
05444 }
05445
05446
05447
05448 if (ast_fileexists(fn, NULL, NULL) > 0) {
05449 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
05450 }
05451
05452
05453 while (tmpptr) {
05454 struct ast_vm_user recipu, *recip;
05455 char *exten, *cntx;
05456
05457 exten = strsep(&tmpptr, "&");
05458 cntx = strchr(exten, '@');
05459 if (cntx) {
05460 *cntx = '\0';
05461 cntx++;
05462 }
05463 if ((recip = find_user(&recipu, cntx, exten))) {
05464 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
05465 free_user(recip);
05466 }
05467 }
05468 #ifndef IMAP_STORAGE
05469 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05470
05471 char sfn[PATH_MAX];
05472 char dfn[PATH_MAX];
05473 int x;
05474
05475 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
05476 x = last_message_index(vmu, urgdir) + 1;
05477 make_file(sfn, sizeof(sfn), dir, msgnum);
05478 make_file(dfn, sizeof(dfn), urgdir, x);
05479 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
05480 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
05481
05482 ast_copy_string(fn, dfn, sizeof(fn));
05483 msgnum = x;
05484 }
05485 #endif
05486
05487 if (ast_fileexists(fn, NULL, NULL)) {
05488 #ifdef IMAP_STORAGE
05489 notify_new_message(chan, vmu, vms, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
05490 #else
05491 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
05492 #endif
05493 }
05494
05495
05496 if (ast_fileexists(fn, NULL, NULL)) {
05497 DISPOSE(dir, msgnum);
05498 }
05499 }
05500 }
05501 } else {
05502 inprocess_count(vmu->mailbox, vmu->context, -1);
05503 }
05504 if (res == '0') {
05505 goto transfer;
05506 } else if (res > 0)
05507 res = 0;
05508
05509 if (duration < vmminsecs)
05510
05511 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05512 else
05513 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05514 } else
05515 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
05516 leave_vm_out:
05517 free_user(vmu);
05518
05519 #ifdef IMAP_STORAGE
05520
05521 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n",expungeonhangup);
05522 if (expungeonhangup == 1) {
05523 ast_mutex_lock(&vms->lock);
05524 #ifdef HAVE_IMAP_TK2006
05525 if (LEVELUIDPLUS (vms->mailstream)) {
05526 mail_expunge_full(vms->mailstream,NIL,EX_UID);
05527 } else
05528 #endif
05529 mail_expunge(vms->mailstream);
05530 ast_mutex_unlock(&vms->lock);
05531 }
05532 #endif
05533
05534 ast_free(tmp);
05535 return res;
05536 }
05537
05538 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
05539 {
05540 int d;
05541 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
05542 return d;
05543 }
05544
05545 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
05546 {
05547 #ifdef IMAP_STORAGE
05548
05549
05550 char sequence[10];
05551 char mailbox[256];
05552 int res;
05553
05554
05555 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
05556
05557 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(box));
05558 ast_mutex_lock(&vms->lock);
05559
05560 if (box == OLD_FOLDER) {
05561 mail_setflag(vms->mailstream, sequence, "\\Seen");
05562 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
05563 } else if (box == NEW_FOLDER) {
05564 mail_setflag(vms->mailstream, sequence, "\\Unseen");
05565 mail_clearflag(vms->mailstream, sequence, "\\Seen");
05566 }
05567 if (!strcasecmp(mbox(NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
05568 ast_mutex_unlock(&vms->lock);
05569 return 0;
05570 }
05571
05572 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
05573 ast_debug(5, "Checking if folder exists: %s\n",mailbox);
05574 if (mail_create(vms->mailstream, mailbox) == NIL)
05575 ast_debug(5, "Folder exists.\n");
05576 else
05577 ast_log(AST_LOG_NOTICE, "Folder %s created!\n",mbox(box));
05578 res = !mail_copy(vms->mailstream, sequence, (char *)mbox(box));
05579 ast_mutex_unlock(&vms->lock);
05580 return res;
05581 #else
05582 char *dir = vms->curdir;
05583 char *username = vms->username;
05584 char *context = vmu->context;
05585 char sfn[PATH_MAX];
05586 char dfn[PATH_MAX];
05587 char ddir[PATH_MAX];
05588 const char *dbox = mbox(box);
05589 int x, i;
05590 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
05591
05592 if (vm_lock_path(ddir))
05593 return ERROR_LOCK_PATH;
05594
05595 x = last_message_index(vmu, ddir) + 1;
05596
05597 if (box == 10 && x >= vmu->maxdeletedmsg) {
05598 x--;
05599 for (i = 1; i <= x; i++) {
05600
05601 make_file(sfn, sizeof(sfn), ddir, i);
05602 make_file(dfn, sizeof(dfn), ddir, i - 1);
05603 if (EXISTS(ddir, i, sfn, NULL)) {
05604 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
05605 } else
05606 break;
05607 }
05608 } else {
05609 if (x >= vmu->maxmsg) {
05610 ast_unlock_path(ddir);
05611 return -1;
05612 }
05613 }
05614 make_file(sfn, sizeof(sfn), dir, msg);
05615 make_file(dfn, sizeof(dfn), ddir, x);
05616 if (strcmp(sfn, dfn)) {
05617 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
05618 }
05619 ast_unlock_path(ddir);
05620 #endif
05621 return 0;
05622 }
05623
05624 static int adsi_logo(unsigned char *buf)
05625 {
05626 int bytes = 0;
05627 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
05628 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
05629 return bytes;
05630 }
05631
05632 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
05633 {
05634 unsigned char buf[256];
05635 int bytes=0;
05636 int x;
05637 char num[5];
05638
05639 *useadsi = 0;
05640 bytes += ast_adsi_data_mode(buf + bytes);
05641 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05642
05643 bytes = 0;
05644 bytes += adsi_logo(buf);
05645 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
05646 #ifdef DISPLAY
05647 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
05648 #endif
05649 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05650 bytes += ast_adsi_data_mode(buf + bytes);
05651 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05652
05653 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
05654 bytes = 0;
05655 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
05656 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
05657 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05658 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05659 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05660 return 0;
05661 }
05662
05663 #ifdef DISPLAY
05664
05665 bytes = 0;
05666 bytes += ast_adsi_logo(buf);
05667 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
05668 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
05669 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05670 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05671 #endif
05672 bytes = 0;
05673 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
05674 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
05675 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
05676 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
05677 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
05678 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
05679 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05680
05681 #ifdef DISPLAY
05682
05683 bytes = 0;
05684 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
05685 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05686
05687 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05688 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05689 #endif
05690
05691 bytes = 0;
05692
05693 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
05694 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
05695 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
05696 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
05697 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
05698 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
05699 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05700
05701 #ifdef DISPLAY
05702
05703 bytes = 0;
05704 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
05705 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05706 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05707 #endif
05708
05709 bytes = 0;
05710 for (x=0;x<5;x++) {
05711 snprintf(num, sizeof(num), "%d", x);
05712 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
05713 }
05714 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
05715 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05716
05717 #ifdef DISPLAY
05718
05719 bytes = 0;
05720 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
05721 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05722 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05723 #endif
05724
05725 if (ast_adsi_end_download(chan)) {
05726 bytes = 0;
05727 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
05728 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
05729 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05730 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05731 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05732 return 0;
05733 }
05734 bytes = 0;
05735 bytes += ast_adsi_download_disconnect(buf + bytes);
05736 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05737 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05738
05739 ast_debug(1, "Done downloading scripts...\n");
05740
05741 #ifdef DISPLAY
05742
05743 bytes = 0;
05744 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
05745 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05746 #endif
05747 ast_debug(1, "Restarting session...\n");
05748
05749 bytes = 0;
05750
05751 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
05752 *useadsi = 1;
05753 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
05754 } else
05755 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
05756
05757 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05758 return 0;
05759 }
05760
05761 static void adsi_begin(struct ast_channel *chan, int *useadsi)
05762 {
05763 int x;
05764 if (!ast_adsi_available(chan))
05765 return;
05766 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
05767 if (x < 0)
05768 return;
05769 if (!x) {
05770 if (adsi_load_vmail(chan, useadsi)) {
05771 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
05772 return;
05773 }
05774 } else
05775 *useadsi = 1;
05776 }
05777
05778 static void adsi_login(struct ast_channel *chan)
05779 {
05780 unsigned char buf[256];
05781 int bytes=0;
05782 unsigned char keys[8];
05783 int x;
05784 if (!ast_adsi_available(chan))
05785 return;
05786
05787 for (x=0;x<8;x++)
05788 keys[x] = 0;
05789
05790 keys[3] = ADSI_KEY_APPS + 3;
05791
05792 bytes += adsi_logo(buf + bytes);
05793 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
05794 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
05795 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05796 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
05797 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
05798 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
05799 bytes += ast_adsi_set_keys(buf + bytes, keys);
05800 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05801 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05802 }
05803
05804 static void adsi_password(struct ast_channel *chan)
05805 {
05806 unsigned char buf[256];
05807 int bytes=0;
05808 unsigned char keys[8];
05809 int x;
05810 if (!ast_adsi_available(chan))
05811 return;
05812
05813 for (x=0;x<8;x++)
05814 keys[x] = 0;
05815
05816 keys[3] = ADSI_KEY_APPS + 3;
05817
05818 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05819 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
05820 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
05821 bytes += ast_adsi_set_keys(buf + bytes, keys);
05822 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05823 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05824 }
05825
05826 static void adsi_folders(struct ast_channel *chan, int start, char *label)
05827 {
05828 unsigned char buf[256];
05829 int bytes=0;
05830 unsigned char keys[8];
05831 int x,y;
05832
05833 if (!ast_adsi_available(chan))
05834 return;
05835
05836 for (x=0;x<5;x++) {
05837 y = ADSI_KEY_APPS + 12 + start + x;
05838 if (y > ADSI_KEY_APPS + 12 + 4)
05839 y = 0;
05840 keys[x] = ADSI_KEY_SKT | y;
05841 }
05842 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
05843 keys[6] = 0;
05844 keys[7] = 0;
05845
05846 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
05847 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
05848 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05849 bytes += ast_adsi_set_keys(buf + bytes, keys);
05850 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05851
05852 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05853 }
05854
05855 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
05856 {
05857 int bytes=0;
05858 unsigned char buf[256];
05859 char buf1[256], buf2[256];
05860 char fn2[PATH_MAX];
05861
05862 char cid[256]="";
05863 char *val;
05864 char *name, *num;
05865 char datetime[21]="";
05866 FILE *f;
05867
05868 unsigned char keys[8];
05869
05870 int x;
05871
05872 if (!ast_adsi_available(chan))
05873 return;
05874
05875
05876 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
05877 f = fopen(fn2, "r");
05878 if (f) {
05879 while (!feof(f)) {
05880 if (!fgets((char *)buf, sizeof(buf), f)) {
05881 continue;
05882 }
05883 if (!feof(f)) {
05884 char *stringp=NULL;
05885 stringp = (char *)buf;
05886 strsep(&stringp, "=");
05887 val = strsep(&stringp, "=");
05888 if (!ast_strlen_zero(val)) {
05889 if (!strcmp((char *)buf, "callerid"))
05890 ast_copy_string(cid, val, sizeof(cid));
05891 if (!strcmp((char *)buf, "origdate"))
05892 ast_copy_string(datetime, val, sizeof(datetime));
05893 }
05894 }
05895 }
05896 fclose(f);
05897 }
05898
05899 for (x=0;x<5;x++)
05900 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05901 keys[6] = 0x0;
05902 keys[7] = 0x0;
05903
05904 if (!vms->curmsg) {
05905
05906 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05907 }
05908 if (vms->curmsg >= vms->lastmsg) {
05909
05910 if (vms->curmsg) {
05911
05912 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05913 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05914
05915 } else {
05916
05917 keys[3] = 1;
05918 }
05919 }
05920
05921 if (!ast_strlen_zero(cid)) {
05922 ast_callerid_parse(cid, &name, &num);
05923 if (!name)
05924 name = num;
05925 } else
05926 name = "Unknown Caller";
05927
05928
05929
05930 if (vms->deleted[vms->curmsg])
05931 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05932
05933
05934 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05935 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
05936 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
05937 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
05938
05939 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05940 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05941 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
05942 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
05943 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05944 bytes += ast_adsi_set_keys(buf + bytes, keys);
05945 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05946
05947 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05948 }
05949
05950 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
05951 {
05952 int bytes=0;
05953 unsigned char buf[256];
05954 unsigned char keys[8];
05955
05956 int x;
05957
05958 if (!ast_adsi_available(chan))
05959 return;
05960
05961
05962 for (x=0;x<5;x++)
05963 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05964
05965 keys[6] = 0x0;
05966 keys[7] = 0x0;
05967
05968 if (!vms->curmsg) {
05969
05970 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05971 }
05972 if (vms->curmsg >= vms->lastmsg) {
05973
05974 if (vms->curmsg) {
05975
05976 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05977 } else {
05978
05979 keys[3] = 1;
05980 }
05981 }
05982
05983
05984 if (vms->deleted[vms->curmsg])
05985 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05986
05987
05988 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05989 bytes += ast_adsi_set_keys(buf + bytes, keys);
05990 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05991
05992 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05993 }
05994
05995 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
05996 {
05997 unsigned char buf[256] = "";
05998 char buf1[256] = "", buf2[256] = "";
05999 int bytes=0;
06000 unsigned char keys[8];
06001 int x;
06002
06003 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06004 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06005 if (!ast_adsi_available(chan))
06006 return;
06007 if (vms->newmessages) {
06008 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06009 if (vms->oldmessages) {
06010 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06011 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06012 } else {
06013 snprintf(buf2, sizeof(buf2), "%s.", newm);
06014 }
06015 } else if (vms->oldmessages) {
06016 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06017 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06018 } else {
06019 strcpy(buf1, "You have no messages.");
06020 buf2[0] = ' ';
06021 buf2[1] = '\0';
06022 }
06023 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06024 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06025 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06026
06027 for (x=0;x<6;x++)
06028 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06029 keys[6] = 0;
06030 keys[7] = 0;
06031
06032
06033 if (vms->lastmsg < 0)
06034 keys[0] = 1;
06035 bytes += ast_adsi_set_keys(buf + bytes, keys);
06036
06037 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06038
06039 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06040 }
06041
06042 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06043 {
06044 unsigned char buf[256] = "";
06045 char buf1[256] = "", buf2[256] = "";
06046 int bytes=0;
06047 unsigned char keys[8];
06048 int x;
06049
06050 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06051
06052 if (!ast_adsi_available(chan))
06053 return;
06054
06055
06056 for (x=0;x<6;x++)
06057 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06058
06059 keys[6] = 0;
06060 keys[7] = 0;
06061
06062 if ((vms->lastmsg + 1) < 1)
06063 keys[0] = 0;
06064
06065 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06066 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06067
06068 if (vms->lastmsg + 1)
06069 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06070 else
06071 strcpy(buf2, "no messages.");
06072 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06073 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06074 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06075 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06076 bytes += ast_adsi_set_keys(buf + bytes, keys);
06077
06078 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06079
06080 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06081
06082 }
06083
06084
06085
06086
06087
06088
06089
06090
06091
06092
06093
06094
06095
06096
06097
06098 static void adsi_goodbye(struct ast_channel *chan)
06099 {
06100 unsigned char buf[256];
06101 int bytes=0;
06102
06103 if (!ast_adsi_available(chan))
06104 return;
06105 bytes += adsi_logo(buf + bytes);
06106 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06107 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06108 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06109 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06110
06111 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06112 }
06113
06114
06115
06116
06117
06118 static int get_folder(struct ast_channel *chan, int start)
06119 {
06120 int x;
06121 int d;
06122 char fn[PATH_MAX];
06123 d = ast_play_and_wait(chan, "vm-press");
06124 if (d)
06125 return d;
06126 for (x = start; x< 5; x++) {
06127 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06128 return d;
06129 d = ast_play_and_wait(chan, "vm-for");
06130 if (d)
06131 return d;
06132 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
06133 d = vm_play_folder_name(chan, fn);
06134 if (d)
06135 return d;
06136 d = ast_waitfordigit(chan, 500);
06137 if (d)
06138 return d;
06139 }
06140 d = ast_play_and_wait(chan, "vm-tocancel");
06141 if (d)
06142 return d;
06143 d = ast_waitfordigit(chan, 4000);
06144 return d;
06145 }
06146
06147
06148
06149
06150
06151
06152
06153
06154
06155
06156
06157
06158
06159 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06160 {
06161 int res = 0;
06162 res = ast_play_and_wait(chan, fn);
06163 while (((res < '0') || (res > '9')) &&
06164 (res != '#') && (res >= 0)) {
06165 res = get_folder(chan, 0);
06166 }
06167 return res;
06168 }
06169
06170
06171
06172
06173
06174
06175
06176
06177
06178
06179
06180
06181
06182
06183
06184
06185
06186
06187 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06188 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06189 {
06190 #ifdef IMAP_STORAGE
06191 int res;
06192 #endif
06193 int cmd = 0;
06194 int retries = 0, prepend_duration = 0, already_recorded = 0;
06195 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06196 char textfile[PATH_MAX];
06197 struct ast_config *msg_cfg;
06198 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06199 #ifndef IMAP_STORAGE
06200 signed char zero_gain = 0;
06201 #endif
06202 const char *duration_str;
06203
06204
06205 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06206 strcpy(textfile, msgfile);
06207 strcpy(backup, msgfile);
06208 strcpy(backup_textfile, msgfile);
06209 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06210 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06211 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06212
06213 if ((msg_cfg = ast_config_load(textfile, config_flags)) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06214 *duration = atoi(duration_str);
06215 } else {
06216 *duration = 0;
06217 }
06218
06219 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06220 if (cmd)
06221 retries = 0;
06222 switch (cmd) {
06223 case '1':
06224
06225 #ifdef IMAP_STORAGE
06226
06227 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06228 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06229 res = ast_play_and_wait(chan, INTRO);
06230 res = ast_play_and_wait(chan, "beep");
06231 res = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *)duration, NULL, record_gain, vms, flag);
06232 cmd = 't';
06233 #else
06234
06235
06236
06237 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06238 strcpy(textfile, msgfile);
06239 strncat(textfile, ".txt", sizeof(textfile) - 1);
06240 *duration = 0;
06241
06242
06243 if (!msg_cfg) {
06244 cmd = 0;
06245 break;
06246 }
06247
06248
06249 if (already_recorded) {
06250 ast_filecopy(backup, msgfile, NULL);
06251 copy(backup_textfile, textfile);
06252 }
06253 else {
06254 ast_filecopy(msgfile, backup, NULL);
06255 copy(textfile,backup_textfile);
06256 }
06257 already_recorded = 1;
06258
06259 if (record_gain)
06260 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06261
06262 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, 1, silencethreshold, maxsilence);
06263 if (record_gain)
06264 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06265
06266
06267 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06268 *duration = atoi(duration_str);
06269
06270 if (prepend_duration) {
06271 struct ast_category *msg_cat;
06272
06273 char duration_buf[12];
06274
06275 *duration += prepend_duration;
06276 msg_cat = ast_category_get(msg_cfg, "message");
06277 snprintf(duration_buf, 11, "%ld", *duration);
06278 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06279 config_text_file_save(textfile, msg_cfg, "app_voicemail");
06280 }
06281 }
06282
06283 #endif
06284 break;
06285 case '2':
06286
06287 #ifdef IMAP_STORAGE
06288 *vms->introfn = '\0';
06289 #endif
06290 cmd = 't';
06291 break;
06292 case '*':
06293 cmd = '*';
06294 break;
06295 default:
06296 cmd = ast_play_and_wait(chan,"vm-forwardoptions");
06297
06298 if (!cmd)
06299 cmd = ast_play_and_wait(chan,"vm-starmain");
06300
06301 if (!cmd)
06302 cmd = ast_waitfordigit(chan,6000);
06303 if (!cmd)
06304 retries++;
06305 if (retries > 3)
06306 cmd = 't';
06307 }
06308 }
06309
06310 if (msg_cfg)
06311 ast_config_destroy(msg_cfg);
06312 if (prepend_duration)
06313 *duration = prepend_duration;
06314
06315 if (already_recorded && cmd == -1) {
06316
06317 ast_filerename(backup, msgfile, NULL);
06318 rename(backup_textfile, textfile);
06319 }
06320
06321 if (cmd == 't' || cmd == 'S')
06322 cmd = 0;
06323 return cmd;
06324 }
06325
06326 static void queue_mwi_event(const char *box, int urgent, int new, int old)
06327 {
06328 struct ast_event *event;
06329 char *mailbox, *context;
06330
06331
06332 context = mailbox = ast_strdupa(box);
06333 strsep(&context, "@");
06334 if (ast_strlen_zero(context))
06335 context = "default";
06336
06337 if (!(event = ast_event_new(AST_EVENT_MWI,
06338 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
06339 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
06340 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
06341 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
06342 AST_EVENT_IE_END))) {
06343 return;
06344 }
06345
06346 ast_event_queue_and_cache(event);
06347 }
06348
06349
06350
06351
06352
06353
06354
06355
06356
06357
06358
06359
06360
06361
06362 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag)
06363 {
06364 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
06365 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
06366 const char *category;
06367 char *myserveremail = serveremail;
06368
06369 ast_channel_lock(chan);
06370 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
06371 category = ast_strdupa(category);
06372 }
06373 ast_channel_unlock(chan);
06374
06375 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
06376 make_file(fn, sizeof(fn), todir, msgnum);
06377 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
06378
06379 if (!ast_strlen_zero(vmu->attachfmt)) {
06380 if (strstr(fmt, vmu->attachfmt))
06381 fmt = vmu->attachfmt;
06382 else
06383 ast_log(AST_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);
06384 }
06385
06386
06387 fmt = ast_strdupa(fmt);
06388 stringp = fmt;
06389 strsep(&stringp, "|");
06390
06391 if (!ast_strlen_zero(vmu->serveremail))
06392 myserveremail = vmu->serveremail;
06393
06394 if (!ast_strlen_zero(vmu->email)) {
06395 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
06396 if (!attach_user_voicemail)
06397 attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
06398
06399 if (attach_user_voicemail)
06400 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
06401
06402
06403 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
06404
06405 if (attach_user_voicemail)
06406 DISPOSE(todir, msgnum);
06407 }
06408
06409 if (!ast_strlen_zero(vmu->pager)) {
06410 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, duration, vmu, category, flag);
06411 }
06412
06413 if (ast_test_flag(vmu, VM_DELETE))
06414 DELETE(todir, msgnum, fn, vmu);
06415
06416
06417 if (ast_app_has_voicemail(ext_context, NULL))
06418 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
06419
06420 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
06421
06422 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);
06423 run_externnotify(vmu->context, vmu->mailbox, flag);
06424
06425 #ifdef IMAP_STORAGE
06426 vm_delete(fn);
06427 if (ast_test_flag(vmu, VM_DELETE)) {
06428 vm_imap_delete(NULL, vms->curmsg, vmu);
06429 vms->newmessages--;
06430 }
06431 #endif
06432
06433 return 0;
06434 }
06435
06436
06437
06438
06439
06440
06441
06442
06443
06444
06445
06446
06447
06448
06449
06450
06451
06452
06453
06454
06455
06456
06457
06458
06459
06460
06461
06462 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent)
06463 {
06464 #ifdef IMAP_STORAGE
06465 int todircount=0;
06466 struct vm_state *dstvms;
06467 #endif
06468 char username[70]="";
06469 char fn[PATH_MAX];
06470 char ecodes[16] = "#";
06471 int res = 0, cmd = 0;
06472 struct ast_vm_user *receiver = NULL, *vmtmp;
06473 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
06474 char *stringp;
06475 const char *s;
06476 int saved_messages = 0, found = 0;
06477 int valid_extensions = 0;
06478 char *dir;
06479 int curmsg;
06480 char urgent_str[7] = "";
06481 char tmptxtfile[PATH_MAX];
06482 #ifndef IMAP_STORAGE
06483 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06484 #endif
06485 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
06486 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
06487 }
06488
06489 if (vms == NULL) return -1;
06490 dir = vms->curdir;
06491 curmsg = vms->curmsg;
06492
06493 tmptxtfile[0] = '\0';
06494 while (!res && !valid_extensions) {
06495 int use_directory = 0;
06496 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
06497 int done = 0;
06498 int retries = 0;
06499 cmd=0;
06500 while ((cmd >= 0) && !done ){
06501 if (cmd)
06502 retries = 0;
06503 switch (cmd) {
06504 case '1':
06505 use_directory = 0;
06506 done = 1;
06507 break;
06508 case '2':
06509 use_directory = 1;
06510 done=1;
06511 break;
06512 case '*':
06513 cmd = 't';
06514 done = 1;
06515 break;
06516 default:
06517
06518 cmd = ast_play_and_wait(chan,"vm-forward");
06519 if (!cmd)
06520 cmd = ast_waitfordigit(chan,3000);
06521 if (!cmd)
06522 retries++;
06523 if (retries > 3) {
06524 cmd = 't';
06525 done = 1;
06526 }
06527
06528 }
06529 }
06530 if (cmd < 0 || cmd == 't')
06531 break;
06532 }
06533
06534 if (use_directory) {
06535
06536
06537 char old_context[sizeof(chan->context)];
06538 char old_exten[sizeof(chan->exten)];
06539 int old_priority;
06540 struct ast_app* directory_app;
06541
06542 directory_app = pbx_findapp("Directory");
06543 if (directory_app) {
06544 char vmcontext[256];
06545
06546 memcpy(old_context, chan->context, sizeof(chan->context));
06547 memcpy(old_exten, chan->exten, sizeof(chan->exten));
06548 old_priority = chan->priority;
06549
06550
06551 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
06552 res = pbx_exec(chan, directory_app, vmcontext);
06553
06554 ast_copy_string(username, chan->exten, sizeof(username));
06555
06556
06557 memcpy(chan->context, old_context, sizeof(chan->context));
06558 memcpy(chan->exten, old_exten, sizeof(chan->exten));
06559 chan->priority = old_priority;
06560 } else {
06561 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
06562 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
06563 }
06564 } else {
06565
06566 res = ast_streamfile(chan, "vm-extension", chan->language);
06567 if (res)
06568 break;
06569 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
06570 break;
06571 }
06572
06573
06574 if (ast_strlen_zero(username))
06575 continue;
06576 stringp = username;
06577 s = strsep(&stringp, "*");
06578
06579 valid_extensions = 1;
06580 while (s) {
06581 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
06582 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
06583 found++;
06584 } else {
06585
06586
06587
06588
06589
06590 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
06591 free_user(receiver);
06592 }
06593 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
06594 valid_extensions = 0;
06595 break;
06596 }
06597
06598
06599 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
06600 RETRIEVE(fn, -1, s, receiver->context);
06601 if (ast_fileexists(fn, NULL, NULL) > 0) {
06602 res = ast_stream_and_wait(chan, fn, ecodes);
06603 if (res) {
06604 DISPOSE(fn, -1);
06605 return res;
06606 }
06607 } else {
06608 res = ast_say_digit_str(chan, s, ecodes, chan->language);
06609 }
06610 DISPOSE(fn, -1);
06611
06612 s = strsep(&stringp, "*");
06613 }
06614
06615 if (valid_extensions)
06616 break;
06617
06618 res = ast_play_and_wait(chan, "pbx-invalid");
06619 }
06620
06621 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
06622 return res;
06623 if (is_new_message == 1) {
06624 struct leave_vm_options leave_options;
06625 char mailbox[AST_MAX_EXTENSION * 2 + 2];
06626 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
06627
06628
06629 memset(&leave_options, 0, sizeof(leave_options));
06630 leave_options.record_gain = record_gain;
06631 cmd = leave_voicemail(chan, mailbox, &leave_options);
06632 } else {
06633
06634 long duration = 0;
06635 struct vm_state vmstmp;
06636 memcpy(&vmstmp, vms, sizeof(vmstmp));
06637
06638 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
06639
06640 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
06641 if (!cmd) {
06642 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
06643 #ifdef IMAP_STORAGE
06644 int attach_user_voicemail;
06645 char *myserveremail = serveremail;
06646
06647
06648 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
06649 if (!dstvms) {
06650 dstvms = create_vm_state_from_user(vmtmp);
06651 }
06652 if (dstvms) {
06653 init_mailstream(dstvms, 0);
06654 if (!dstvms->mailstream) {
06655 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
06656 } else {
06657 STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
06658 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
06659 }
06660 } else {
06661 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
06662 }
06663 if (!ast_strlen_zero(vmtmp->serveremail))
06664 myserveremail = vmtmp->serveremail;
06665 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
06666
06667 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, dstvms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan, NULL, urgent_str);
06668 #else
06669 copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
06670 #endif
06671 saved_messages++;
06672 AST_LIST_REMOVE_CURRENT(list);
06673 free_user(vmtmp);
06674 if (res)
06675 break;
06676 }
06677 AST_LIST_TRAVERSE_SAFE_END;
06678 if (saved_messages > 0) {
06679
06680
06681
06682
06683
06684
06685
06686
06687 #ifdef IMAP_STORAGE
06688
06689 if (ast_strlen_zero(vmstmp.introfn))
06690 #endif
06691 res = ast_play_and_wait(chan, "vm-msgsaved");
06692 }
06693 #ifndef IMAP_STORAGE
06694
06695 make_file(msgfile, sizeof(msgfile), dir, curmsg);
06696 strcpy(textfile, msgfile);
06697 strcpy(backup, msgfile);
06698 strcpy(backup_textfile, msgfile);
06699 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06700 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06701 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06702 if (ast_fileexists(backup, NULL, NULL) > 0) {
06703 ast_filerename(backup, msgfile, NULL);
06704 rename(backup_textfile, textfile);
06705 }
06706 #endif
06707 }
06708 DISPOSE(dir, curmsg);
06709 }
06710
06711
06712 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)))
06713 free_user(vmtmp);
06714 return res ? res : cmd;
06715 }
06716
06717 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
06718 {
06719 int res;
06720 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
06721 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
06722 return res;
06723 }
06724
06725 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
06726 {
06727 return ast_control_streamfile(chan, file, listen_control_forward_key, listen_control_reverse_key, listen_control_stop_key, listen_control_pause_key, listen_control_restart_key, skipms, NULL);
06728 }
06729
06730 static int play_message_category(struct ast_channel *chan, const char *category)
06731 {
06732 int res = 0;
06733
06734 if (!ast_strlen_zero(category))
06735 res = ast_play_and_wait(chan, category);
06736
06737 if (res) {
06738 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
06739 res = 0;
06740 }
06741
06742 return res;
06743 }
06744
06745 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
06746 {
06747 int res = 0;
06748 struct vm_zone *the_zone = NULL;
06749 time_t t;
06750
06751 if (ast_get_time_t(origtime, &t, 0, NULL)) {
06752 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
06753 return 0;
06754 }
06755
06756
06757 if (!ast_strlen_zero(vmu->zonetag)) {
06758
06759 struct vm_zone *z;
06760 AST_LIST_LOCK(&zones);
06761 AST_LIST_TRAVERSE(&zones, z, list) {
06762 if (!strcmp(z->name, vmu->zonetag)) {
06763 the_zone = z;
06764 break;
06765 }
06766 }
06767 AST_LIST_UNLOCK(&zones);
06768 }
06769
06770
06771 #if 0
06772
06773 ast_localtime(&t, &time_now, NULL);
06774 tv_now = ast_tvnow();
06775 ast_localtime(&tv_now, &time_then, NULL);
06776
06777
06778 if (time_now.tm_year == time_then.tm_year)
06779 snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
06780 else
06781 snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
06782 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
06783
06784
06785 #endif
06786 if (the_zone) {
06787 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
06788 } else if (!strncasecmp(chan->language, "de", 2)) {
06789 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
06790 } else if (!strncasecmp(chan->language, "gr", 2)) {
06791 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
06792 } else if (!strncasecmp(chan->language, "it", 2)) {
06793 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);
06794 } else if (!strncasecmp(chan->language, "nl", 2)) {
06795 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
06796 } else if (!strncasecmp(chan->language, "no", 2)) {
06797 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
06798 } else if (!strncasecmp(chan->language, "pl", 2)) {
06799 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
06800 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
06801 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);
06802 } else if (!strncasecmp(chan->language, "se", 2)) {
06803 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
06804 } else if (!strncasecmp(chan->language, "zh", 2)) {
06805 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
06806 } else {
06807 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
06808 }
06809 #if 0
06810 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
06811 #endif
06812 return res;
06813 }
06814
06815
06816
06817 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
06818 {
06819 int res = 0;
06820 int i;
06821 char *callerid, *name;
06822 char prefile[PATH_MAX] = "";
06823
06824
06825
06826
06827
06828
06829
06830
06831
06832 if ((cid == NULL)||(context == NULL))
06833 return res;
06834
06835
06836 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
06837 ast_callerid_parse(cid, &name, &callerid);
06838 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
06839
06840
06841 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
06842 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
06843 if ((strcmp(cidinternalcontexts[i], context) == 0))
06844 break;
06845 }
06846 if (i != MAX_NUM_CID_CONTEXTS){
06847 if (!res) {
06848 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
06849 if (!ast_strlen_zero(prefile)) {
06850
06851 if (ast_fileexists(prefile, NULL, NULL) > 0) {
06852 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
06853 if (!callback)
06854 res = wait_file2(chan, vms, "vm-from");
06855 res = ast_stream_and_wait(chan, prefile, "");
06856 } else {
06857 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
06858
06859 if (!callback)
06860 res = wait_file2(chan, vms, "vm-from-extension");
06861 res = ast_say_digit_str(chan, callerid, "", chan->language);
06862 }
06863 }
06864 }
06865 } else if (!res) {
06866 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
06867
06868 if (!callback)
06869 res = wait_file2(chan, vms, "vm-from-phonenumber");
06870 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
06871 }
06872 } else {
06873
06874 ast_debug(1, "VM-CID: From an unknown number\n");
06875
06876 res = wait_file2(chan, vms, "vm-unknown-caller");
06877 }
06878 return res;
06879 }
06880
06881 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
06882 {
06883 int res = 0;
06884 int durationm;
06885 int durations;
06886
06887 if (duration == NULL)
06888 return res;
06889
06890
06891 durations=atoi(duration);
06892 durationm=(durations / 60);
06893
06894 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
06895
06896 if ((!res) && (durationm >= minduration)) {
06897 res = wait_file2(chan, vms, "vm-duration");
06898
06899
06900 if (!strncasecmp(chan->language, "pl", 2)) {
06901 div_t num = div(durationm, 10);
06902
06903 if (durationm == 1) {
06904 res = ast_play_and_wait(chan, "digits/1z");
06905 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
06906 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06907 if (num.rem == 2) {
06908 if (!num.quot) {
06909 res = ast_play_and_wait(chan, "digits/2-ie");
06910 } else {
06911 res = say_and_wait(chan, durationm - 2 , chan->language);
06912 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06913 }
06914 } else {
06915 res = say_and_wait(chan, durationm, chan->language);
06916 }
06917 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
06918 } else {
06919 res = say_and_wait(chan, durationm, chan->language);
06920 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
06921 }
06922
06923 } else {
06924 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
06925 res = wait_file2(chan, vms, "vm-minutes");
06926 }
06927 }
06928 return res;
06929 }
06930
06931 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
06932 {
06933 int res = 0;
06934 char filename[256], *cid;
06935 const char *origtime, *context, *category, *duration, *flag;
06936 struct ast_config *msg_cfg;
06937 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06938
06939 vms->starting = 0;
06940 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
06941 adsi_message(chan, vms);
06942 if (!vms->curmsg)
06943 res = wait_file2(chan, vms, "vm-first");
06944 else if (vms->curmsg == vms->lastmsg)
06945 res = wait_file2(chan, vms, "vm-last");
06946
06947 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
06948 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
06949 msg_cfg = ast_config_load(filename, config_flags);
06950 if (!msg_cfg) {
06951 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
06952 return 0;
06953 }
06954 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
06955
06956
06957 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06958 res = wait_file2(chan, vms, "vm-Urgent");
06959 }
06960
06961 if (!res) {
06962
06963 if (!strncasecmp(chan->language, "pl", 2)) {
06964 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
06965 int ten, one;
06966 char nextmsg[256];
06967 ten = (vms->curmsg + 1) / 10;
06968 one = (vms->curmsg + 1) % 10;
06969
06970 if (vms->curmsg < 20) {
06971 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
06972 res = wait_file2(chan, vms, nextmsg);
06973 } else {
06974 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
06975 res = wait_file2(chan, vms, nextmsg);
06976 if (one > 0) {
06977 if (!res) {
06978 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
06979 res = wait_file2(chan, vms, nextmsg);
06980 }
06981 }
06982 }
06983 }
06984 if (!res)
06985 res = wait_file2(chan, vms, "vm-message");
06986
06987 } else if (!strncasecmp(chan->language, "he", 2)) {
06988 if (!vms->curmsg) {
06989 res = wait_file2(chan, vms, "vm-message");
06990 res = wait_file2(chan, vms, "vm-first");
06991 } else if (vms->curmsg == vms->lastmsg) {
06992 res = wait_file2(chan, vms, "vm-message");
06993 res = wait_file2(chan, vms, "vm-last");
06994 } else {
06995 res = wait_file2(chan, vms, "vm-message");
06996 res = wait_file2(chan, vms, "vm-number");
06997 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
06998 }
06999 } else {
07000 if (!strncasecmp(chan->language, "se", 2)) {
07001 res = wait_file2(chan, vms, "vm-meddelandet");
07002 } else {
07003 res = wait_file2(chan, vms, "vm-message");
07004 }
07005 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07006 if (!res) {
07007 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07008 }
07009 }
07010 }
07011 }
07012
07013 if (!msg_cfg) {
07014 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07015 return 0;
07016 }
07017
07018 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07019 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07020 DISPOSE(vms->curdir, vms->curmsg);
07021 ast_config_destroy(msg_cfg);
07022 return 0;
07023 }
07024
07025 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07026 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07027 category = ast_variable_retrieve(msg_cfg, "message", "category");
07028
07029 context = ast_variable_retrieve(msg_cfg, "message", "context");
07030 if (!strncasecmp("macro",context,5))
07031 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
07032 if (!res) {
07033 res = play_message_category(chan, category);
07034 }
07035 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
07036 res = play_message_datetime(chan, vmu, origtime, filename);
07037 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
07038 res = play_message_callerid(chan, vms, cid, context, 0);
07039 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
07040 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07041
07042 if (res == '1')
07043 res = 0;
07044 ast_config_destroy(msg_cfg);
07045
07046 if (!res) {
07047 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07048 vms->heard[vms->curmsg] = 1;
07049 #ifdef IMAP_STORAGE
07050
07051
07052
07053 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07054 wait_file(chan, vms, vms->introfn);
07055 }
07056 #endif
07057 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07058 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07059 res = 0;
07060 }
07061 }
07062 DISPOSE(vms->curdir, vms->curmsg);
07063 return res;
07064 }
07065
07066 #ifdef IMAP_STORAGE
07067 static int imap_remove_file(char *dir, int msgnum)
07068 {
07069 char fn[PATH_MAX];
07070 char full_fn[PATH_MAX];
07071 char intro[PATH_MAX] = {0,};
07072
07073 if (msgnum > -1) {
07074 make_file(fn, sizeof(fn), dir, msgnum);
07075 snprintf(intro, sizeof(intro), "%sintro", fn);
07076 } else
07077 ast_copy_string(fn, dir, sizeof(fn));
07078
07079 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07080 ast_filedelete(fn, NULL);
07081 if (!ast_strlen_zero(intro)) {
07082 ast_filedelete(intro, NULL);
07083 }
07084 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07085 unlink(full_fn);
07086 }
07087 return 0;
07088 }
07089
07090
07091
07092 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07093 {
07094 char *file, *filename;
07095 char *attachment;
07096 char arg[10];
07097 int i;
07098 BODY* body;
07099
07100
07101 file = strrchr(ast_strdupa(dir), '/');
07102 if (file)
07103 *file++ = '\0';
07104 else {
07105 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07106 return -1;
07107 }
07108
07109 ast_mutex_lock(&vms->lock);
07110 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07111 mail_fetchstructure(vms->mailstream, i + 1, &body);
07112
07113 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07114 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07115 } else {
07116 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07117 ast_mutex_unlock(&vms->lock);
07118 return -1;
07119 }
07120 filename = strsep(&attachment, ".");
07121 if (!strcmp(filename, file)) {
07122 sprintf (arg,"%d", i+1);
07123 mail_setflag (vms->mailstream,arg,"\\DELETED");
07124 }
07125 }
07126 mail_expunge(vms->mailstream);
07127 ast_mutex_unlock(&vms->lock);
07128 return 0;
07129 }
07130
07131 #else
07132 #ifndef IMAP_STORAGE
07133 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07134 {
07135 int count_msg, last_msg;
07136
07137 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
07138
07139
07140
07141
07142 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07143
07144
07145 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07146
07147 count_msg = count_messages(vmu, vms->curdir);
07148 if (count_msg < 0)
07149 return count_msg;
07150 else
07151 vms->lastmsg = count_msg - 1;
07152
07153
07154
07155
07156
07157
07158
07159
07160 if (vm_lock_path(vms->curdir)) {
07161 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07162 return -1;
07163 }
07164
07165 last_msg = last_message_index(vmu, vms->curdir);
07166 ast_unlock_path(vms->curdir);
07167
07168 if (last_msg < 0)
07169 return last_msg;
07170
07171 return 0;
07172 }
07173 #endif
07174 #endif
07175
07176 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07177 {
07178 int x = 0;
07179 #ifndef IMAP_STORAGE
07180 int res = 0, nummsg;
07181 char fn2[PATH_MAX];
07182 #endif
07183
07184 if (vms->lastmsg <= -1)
07185 goto done;
07186
07187 vms->curmsg = -1;
07188 #ifndef IMAP_STORAGE
07189
07190 if (vm_lock_path(vms->curdir))
07191 return ERROR_LOCK_PATH;
07192
07193 for (x = 0; x < vmu->maxmsg; x++) {
07194 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07195
07196 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07197 if (!EXISTS(vms->curdir, x, vms->fn, NULL))
07198 break;
07199 vms->curmsg++;
07200 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07201 if (strcmp(vms->fn, fn2)) {
07202 RENAME(vms->curdir, x, vmu->mailbox,vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07203 }
07204 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07205
07206 res = save_to_folder(vmu, vms, x, 1);
07207 if (res == ERROR_LOCK_PATH) {
07208
07209 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07210 vms->deleted[x] = 0;
07211 vms->heard[x] = 0;
07212 --x;
07213 }
07214 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07215
07216 res = save_to_folder(vmu, vms, x, 10);
07217 if (res == ERROR_LOCK_PATH) {
07218
07219 vms->deleted[x] = 0;
07220 vms->heard[x] = 0;
07221 --x;
07222 }
07223 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07224
07225
07226 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07227 if (EXISTS(vms->curdir, x, vms->fn, NULL))
07228 DELETE(vms->curdir, x, vms->fn, vmu);
07229 }
07230 }
07231
07232
07233 nummsg = x - 1;
07234 for (x = vms->curmsg + 1; x <= nummsg; x++) {
07235 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07236 if (EXISTS(vms->curdir, x, vms->fn, NULL))
07237 DELETE(vms->curdir, x, vms->fn, vmu);
07238 }
07239 ast_unlock_path(vms->curdir);
07240 #else
07241 if (vms->deleted) {
07242 for (x=0;x < vmu->maxmsg;x++) {
07243 if (vms->deleted[x]) {
07244 ast_debug(3,"IMAP delete of %d\n",x);
07245 DELETE(vms->curdir, x, vms->fn, vmu);
07246 }
07247 }
07248 }
07249 #endif
07250
07251 done:
07252 if (vms->deleted)
07253 memset(vms->deleted, 0, vmu->maxmsg * sizeof(int));
07254 if (vms->heard)
07255 memset(vms->heard, 0, vmu->maxmsg * sizeof(int));
07256
07257 return 0;
07258 }
07259
07260
07261
07262
07263
07264
07265
07266 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
07267 {
07268 int cmd;
07269 char *buf;
07270
07271 buf = alloca(strlen(box)+2);
07272 strcpy(buf, box);
07273 strcat(buf,"s");
07274
07275 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
07276 cmd = ast_play_and_wait(chan, buf);
07277 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07278 } else {
07279 cmd = ast_play_and_wait(chan, "vm-messages");
07280 return cmd ? cmd : ast_play_and_wait(chan, box);
07281 }
07282 }
07283
07284 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
07285 {
07286 int cmd;
07287
07288 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
07289 if (!strcasecmp(box, "vm-INBOX"))
07290 cmd = ast_play_and_wait(chan, "vm-new-e");
07291 else
07292 cmd = ast_play_and_wait(chan, "vm-old-e");
07293 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07294 } else {
07295 cmd = ast_play_and_wait(chan, "vm-messages");
07296 return cmd ? cmd : ast_play_and_wait(chan, box);
07297 }
07298 }
07299
07300 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
07301 {
07302 int cmd;
07303
07304 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
07305 cmd = ast_play_and_wait(chan, "vm-messages");
07306 return cmd ? cmd : ast_play_and_wait(chan, box);
07307 } else {
07308 cmd = ast_play_and_wait(chan, box);
07309 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07310 }
07311 }
07312
07313 static int vm_play_folder_name(struct ast_channel *chan, char *box)
07314 {
07315 int cmd;
07316
07317 if ( !strncasecmp(chan->language, "it", 2) ||
07318 !strncasecmp(chan->language, "es", 2) ||
07319 !strncasecmp(chan->language, "pt", 2)) {
07320 cmd = ast_play_and_wait(chan, "vm-messages");
07321 return cmd ? cmd : ast_play_and_wait(chan, box);
07322 } else if (!strncasecmp(chan->language, "gr", 2)) {
07323 return vm_play_folder_name_gr(chan, box);
07324 } else if (!strncasecmp(chan->language, "he", 2)) {
07325 return ast_play_and_wait(chan, box);
07326 } else if (!strncasecmp(chan->language, "pl", 2)) {
07327 return vm_play_folder_name_pl(chan, box);
07328 } else if (!strncasecmp(chan->language, "ua", 2)) {
07329 return vm_play_folder_name_ua(chan, box);
07330 } else {
07331 cmd = ast_play_and_wait(chan, box);
07332 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07333 }
07334 }
07335
07336
07337
07338
07339
07340
07341
07342
07343
07344
07345
07346
07347
07348 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
07349 {
07350 int res = 0;
07351
07352 if (vms->newmessages) {
07353 res = ast_play_and_wait(chan, "vm-youhave");
07354 if (!res)
07355 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
07356 if (!res) {
07357 if ((vms->newmessages == 1)) {
07358 res = ast_play_and_wait(chan, "vm-INBOX");
07359 if (!res)
07360 res = ast_play_and_wait(chan, "vm-message");
07361 } else {
07362 res = ast_play_and_wait(chan, "vm-INBOXs");
07363 if (!res)
07364 res = ast_play_and_wait(chan, "vm-messages");
07365 }
07366 }
07367 } else if (vms->oldmessages){
07368 res = ast_play_and_wait(chan, "vm-youhave");
07369 if (!res)
07370 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
07371 if ((vms->oldmessages == 1)){
07372 res = ast_play_and_wait(chan, "vm-Old");
07373 if (!res)
07374 res = ast_play_and_wait(chan, "vm-message");
07375 } else {
07376 res = ast_play_and_wait(chan, "vm-Olds");
07377 if (!res)
07378 res = ast_play_and_wait(chan, "vm-messages");
07379 }
07380 } else if (!vms->oldmessages && !vms->newmessages)
07381 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
07382 return res;
07383 }
07384
07385
07386
07387
07388
07389
07390
07391
07392
07393
07394
07395
07396
07397
07398
07399
07400
07401
07402
07403
07404
07405
07406
07407
07408
07409
07410
07411
07412
07413
07414
07415
07416
07417
07418
07419
07420
07421
07422
07423
07424
07425
07426
07427
07428
07429
07430
07431
07432
07433
07434
07435
07436
07437
07438
07439
07440
07441
07442 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
07443 {
07444 int res;
07445 int lastnum = 0;
07446
07447 res = ast_play_and_wait(chan, "vm-youhave");
07448
07449 if (!res && vms->newmessages) {
07450 lastnum = vms->newmessages;
07451
07452 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
07453 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
07454 }
07455
07456 if (!res && vms->oldmessages) {
07457 res = ast_play_and_wait(chan, "vm-and");
07458 }
07459 }
07460
07461 if (!res && vms->oldmessages) {
07462 lastnum = vms->oldmessages;
07463
07464 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
07465 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
07466 }
07467 }
07468
07469 if (!res) {
07470 if (lastnum == 0) {
07471 res = ast_play_and_wait(chan, "vm-no");
07472 }
07473 if (!res) {
07474 res = ast_say_counted_noun(chan, lastnum, "vm-message");
07475 }
07476 }
07477
07478 return res;
07479 }
07480
07481
07482 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
07483 {
07484 int res = 0;
07485
07486
07487 if (!res) {
07488 if ((vms->newmessages) || (vms->oldmessages)) {
07489 res = ast_play_and_wait(chan, "vm-youhave");
07490 }
07491
07492
07493
07494
07495
07496 if (vms->newmessages) {
07497 if (!res) {
07498 if (vms->newmessages == 1) {
07499 res = ast_play_and_wait(chan, "vm-INBOX1");
07500 } else {
07501 if (vms->newmessages == 2) {
07502 res = ast_play_and_wait(chan, "vm-shtei");
07503 } else {
07504 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
07505 }
07506 res = ast_play_and_wait(chan, "vm-INBOX");
07507 }
07508 }
07509 if (vms->oldmessages && !res) {
07510 res = ast_play_and_wait(chan, "vm-and");
07511 if (vms->oldmessages == 1) {
07512 res = ast_play_and_wait(chan, "vm-Old1");
07513 } else {
07514 if (vms->oldmessages == 2) {
07515 res = ast_play_and_wait(chan, "vm-shtei");
07516 } else {
07517 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07518 }
07519 res = ast_play_and_wait(chan, "vm-Old");
07520 }
07521 }
07522 }
07523 if (!res && vms->oldmessages && !vms->newmessages) {
07524 if (!res) {
07525 if (vms->oldmessages == 1) {
07526 res = ast_play_and_wait(chan, "vm-Old1");
07527 } else {
07528 if (vms->oldmessages == 2) {
07529 res = ast_play_and_wait(chan, "vm-shtei");
07530 } else {
07531 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07532 }
07533 res = ast_play_and_wait(chan, "vm-Old");
07534 }
07535 }
07536 }
07537 if (!res) {
07538 if (!vms->oldmessages && !vms->newmessages) {
07539 if (!res) {
07540 res = ast_play_and_wait(chan, "vm-nomessages");
07541 }
07542 }
07543 }
07544 }
07545 return res;
07546 }
07547
07548
07549 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
07550 {
07551 int res;
07552
07553
07554 res = ast_play_and_wait(chan, "vm-youhave");
07555 if (!res) {
07556 if (vms->urgentmessages) {
07557 res = say_and_wait(chan, vms->urgentmessages, chan->language);
07558 if (!res)
07559 res = ast_play_and_wait(chan, "vm-Urgent");
07560 if ((vms->oldmessages || vms->newmessages) && !res) {
07561 res = ast_play_and_wait(chan, "vm-and");
07562 } else if (!res) {
07563 if ((vms->urgentmessages == 1))
07564 res = ast_play_and_wait(chan, "vm-message");
07565 else
07566 res = ast_play_and_wait(chan, "vm-messages");
07567 }
07568 }
07569 if (vms->newmessages) {
07570 res = say_and_wait(chan, vms->newmessages, chan->language);
07571 if (!res)
07572 res = ast_play_and_wait(chan, "vm-INBOX");
07573 if (vms->oldmessages && !res)
07574 res = ast_play_and_wait(chan, "vm-and");
07575 else if (!res) {
07576 if ((vms->newmessages == 1))
07577 res = ast_play_and_wait(chan, "vm-message");
07578 else
07579 res = ast_play_and_wait(chan, "vm-messages");
07580 }
07581
07582 }
07583 if (!res && vms->oldmessages) {
07584 res = say_and_wait(chan, vms->oldmessages, chan->language);
07585 if (!res)
07586 res = ast_play_and_wait(chan, "vm-Old");
07587 if (!res) {
07588 if (vms->oldmessages == 1)
07589 res = ast_play_and_wait(chan, "vm-message");
07590 else
07591 res = ast_play_and_wait(chan, "vm-messages");
07592 }
07593 }
07594 if (!res) {
07595 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
07596 res = ast_play_and_wait(chan, "vm-no");
07597 if (!res)
07598 res = ast_play_and_wait(chan, "vm-messages");
07599 }
07600 }
07601 }
07602 return res;
07603 }
07604
07605
07606 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
07607 {
07608
07609 int res;
07610 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
07611 res = ast_play_and_wait(chan, "vm-no") ||
07612 ast_play_and_wait(chan, "vm-message");
07613 else
07614 res = ast_play_and_wait(chan, "vm-youhave");
07615 if (!res && vms->newmessages) {
07616 res = (vms->newmessages == 1) ?
07617 ast_play_and_wait(chan, "digits/un") ||
07618 ast_play_and_wait(chan, "vm-nuovo") ||
07619 ast_play_and_wait(chan, "vm-message") :
07620
07621 say_and_wait(chan, vms->newmessages, chan->language) ||
07622 ast_play_and_wait(chan, "vm-nuovi") ||
07623 ast_play_and_wait(chan, "vm-messages");
07624 if (!res && vms->oldmessages)
07625 res = ast_play_and_wait(chan, "vm-and");
07626 }
07627 if (!res && vms->oldmessages) {
07628 res = (vms->oldmessages == 1) ?
07629 ast_play_and_wait(chan, "digits/un") ||
07630 ast_play_and_wait(chan, "vm-vecchio") ||
07631 ast_play_and_wait(chan, "vm-message") :
07632
07633 say_and_wait(chan, vms->oldmessages, chan->language) ||
07634 ast_play_and_wait(chan, "vm-vecchi") ||
07635 ast_play_and_wait(chan, "vm-messages");
07636 }
07637 return res;
07638 }
07639
07640
07641 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
07642 {
07643
07644 int res;
07645 div_t num;
07646
07647 if (!vms->oldmessages && !vms->newmessages) {
07648 res = ast_play_and_wait(chan, "vm-no");
07649 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07650 return res;
07651 } else {
07652 res = ast_play_and_wait(chan, "vm-youhave");
07653 }
07654
07655 if (vms->newmessages) {
07656 num = div(vms->newmessages, 10);
07657 if (vms->newmessages == 1) {
07658 res = ast_play_and_wait(chan, "digits/1-a");
07659 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
07660 res = res ? res : ast_play_and_wait(chan, "vm-message");
07661 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07662 if (num.rem == 2) {
07663 if (!num.quot) {
07664 res = ast_play_and_wait(chan, "digits/2-ie");
07665 } else {
07666 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
07667 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07668 }
07669 } else {
07670 res = say_and_wait(chan, vms->newmessages, chan->language);
07671 }
07672 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
07673 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07674 } else {
07675 res = say_and_wait(chan, vms->newmessages, chan->language);
07676 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
07677 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07678 }
07679 if (!res && vms->oldmessages)
07680 res = ast_play_and_wait(chan, "vm-and");
07681 }
07682 if (!res && vms->oldmessages) {
07683 num = div(vms->oldmessages, 10);
07684 if (vms->oldmessages == 1) {
07685 res = ast_play_and_wait(chan, "digits/1-a");
07686 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
07687 res = res ? res : ast_play_and_wait(chan, "vm-message");
07688 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07689 if (num.rem == 2) {
07690 if (!num.quot) {
07691 res = ast_play_and_wait(chan, "digits/2-ie");
07692 } else {
07693 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
07694 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07695 }
07696 } else {
07697 res = say_and_wait(chan, vms->oldmessages, chan->language);
07698 }
07699 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
07700 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07701 } else {
07702 res = say_and_wait(chan, vms->oldmessages, chan->language);
07703 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
07704 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07705 }
07706 }
07707
07708 return res;
07709 }
07710
07711
07712 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
07713 {
07714
07715 int res;
07716
07717 res = ast_play_and_wait(chan, "vm-youhave");
07718 if (res)
07719 return res;
07720
07721 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07722 res = ast_play_and_wait(chan, "vm-no");
07723 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07724 return res;
07725 }
07726
07727 if (vms->newmessages) {
07728 if ((vms->newmessages == 1)) {
07729 res = ast_play_and_wait(chan, "digits/ett");
07730 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
07731 res = res ? res : ast_play_and_wait(chan, "vm-message");
07732 } else {
07733 res = say_and_wait(chan, vms->newmessages, chan->language);
07734 res = res ? res : ast_play_and_wait(chan, "vm-nya");
07735 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07736 }
07737 if (!res && vms->oldmessages)
07738 res = ast_play_and_wait(chan, "vm-and");
07739 }
07740 if (!res && vms->oldmessages) {
07741 if (vms->oldmessages == 1) {
07742 res = ast_play_and_wait(chan, "digits/ett");
07743 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
07744 res = res ? res : ast_play_and_wait(chan, "vm-message");
07745 } else {
07746 res = say_and_wait(chan, vms->oldmessages, chan->language);
07747 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
07748 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07749 }
07750 }
07751
07752 return res;
07753 }
07754
07755
07756 static int vm_intro_no(struct ast_channel *chan,struct vm_state *vms)
07757 {
07758
07759 int res;
07760
07761 res = ast_play_and_wait(chan, "vm-youhave");
07762 if (res)
07763 return res;
07764
07765 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07766 res = ast_play_and_wait(chan, "vm-no");
07767 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07768 return res;
07769 }
07770
07771 if (vms->newmessages) {
07772 if ((vms->newmessages == 1)) {
07773 res = ast_play_and_wait(chan, "digits/1");
07774 res = res ? res : ast_play_and_wait(chan, "vm-ny");
07775 res = res ? res : ast_play_and_wait(chan, "vm-message");
07776 } else {
07777 res = say_and_wait(chan, vms->newmessages, chan->language);
07778 res = res ? res : ast_play_and_wait(chan, "vm-nye");
07779 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07780 }
07781 if (!res && vms->oldmessages)
07782 res = ast_play_and_wait(chan, "vm-and");
07783 }
07784 if (!res && vms->oldmessages) {
07785 if (vms->oldmessages == 1) {
07786 res = ast_play_and_wait(chan, "digits/1");
07787 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
07788 res = res ? res : ast_play_and_wait(chan, "vm-message");
07789 } else {
07790 res = say_and_wait(chan, vms->oldmessages, chan->language);
07791 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
07792 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07793 }
07794 }
07795
07796 return res;
07797 }
07798
07799
07800 static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
07801 {
07802
07803 int res;
07804 res = ast_play_and_wait(chan, "vm-youhave");
07805 if (!res) {
07806 if (vms->newmessages) {
07807 if ((vms->newmessages == 1))
07808 res = ast_play_and_wait(chan, "digits/1F");
07809 else
07810 res = say_and_wait(chan, vms->newmessages, chan->language);
07811 if (!res)
07812 res = ast_play_and_wait(chan, "vm-INBOX");
07813 if (vms->oldmessages && !res)
07814 res = ast_play_and_wait(chan, "vm-and");
07815 else if (!res) {
07816 if ((vms->newmessages == 1))
07817 res = ast_play_and_wait(chan, "vm-message");
07818 else
07819 res = ast_play_and_wait(chan, "vm-messages");
07820 }
07821
07822 }
07823 if (!res && vms->oldmessages) {
07824 if (vms->oldmessages == 1)
07825 res = ast_play_and_wait(chan, "digits/1F");
07826 else
07827 res = say_and_wait(chan, vms->oldmessages, chan->language);
07828 if (!res)
07829 res = ast_play_and_wait(chan, "vm-Old");
07830 if (!res) {
07831 if (vms->oldmessages == 1)
07832 res = ast_play_and_wait(chan, "vm-message");
07833 else
07834 res = ast_play_and_wait(chan, "vm-messages");
07835 }
07836 }
07837 if (!res) {
07838 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07839 res = ast_play_and_wait(chan, "vm-no");
07840 if (!res)
07841 res = ast_play_and_wait(chan, "vm-messages");
07842 }
07843 }
07844 }
07845 return res;
07846 }
07847
07848
07849 static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
07850 {
07851
07852 int res;
07853 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07854 res = ast_play_and_wait(chan, "vm-youhaveno");
07855 if (!res)
07856 res = ast_play_and_wait(chan, "vm-messages");
07857 } else {
07858 res = ast_play_and_wait(chan, "vm-youhave");
07859 }
07860 if (!res) {
07861 if (vms->newmessages) {
07862 if (!res) {
07863 if ((vms->newmessages == 1)) {
07864 res = ast_play_and_wait(chan, "digits/1M");
07865 if (!res)
07866 res = ast_play_and_wait(chan, "vm-message");
07867 if (!res)
07868 res = ast_play_and_wait(chan, "vm-INBOXs");
07869 } else {
07870 res = say_and_wait(chan, vms->newmessages, chan->language);
07871 if (!res)
07872 res = ast_play_and_wait(chan, "vm-messages");
07873 if (!res)
07874 res = ast_play_and_wait(chan, "vm-INBOX");
07875 }
07876 }
07877 if (vms->oldmessages && !res)
07878 res = ast_play_and_wait(chan, "vm-and");
07879 }
07880 if (vms->oldmessages) {
07881 if (!res) {
07882 if (vms->oldmessages == 1) {
07883 res = ast_play_and_wait(chan, "digits/1M");
07884 if (!res)
07885 res = ast_play_and_wait(chan, "vm-message");
07886 if (!res)
07887 res = ast_play_and_wait(chan, "vm-Olds");
07888 } else {
07889 res = say_and_wait(chan, vms->oldmessages, chan->language);
07890 if (!res)
07891 res = ast_play_and_wait(chan, "vm-messages");
07892 if (!res)
07893 res = ast_play_and_wait(chan, "vm-Old");
07894 }
07895 }
07896 }
07897 }
07898 return res;
07899 }
07900
07901
07902 static int vm_intro_pt_BR(struct ast_channel *chan,struct vm_state *vms) {
07903
07904 int res;
07905 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07906 res = ast_play_and_wait(chan, "vm-nomessages");
07907 return res;
07908 } else {
07909 res = ast_play_and_wait(chan, "vm-youhave");
07910 }
07911 if (vms->newmessages) {
07912 if (!res)
07913 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
07914 if ((vms->newmessages == 1)) {
07915 if (!res)
07916 res = ast_play_and_wait(chan, "vm-message");
07917 if (!res)
07918 res = ast_play_and_wait(chan, "vm-INBOXs");
07919 } else {
07920 if (!res)
07921 res = ast_play_and_wait(chan, "vm-messages");
07922 if (!res)
07923 res = ast_play_and_wait(chan, "vm-INBOX");
07924 }
07925 if (vms->oldmessages && !res)
07926 res = ast_play_and_wait(chan, "vm-and");
07927 }
07928 if (vms->oldmessages) {
07929 if (!res)
07930 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07931 if (vms->oldmessages == 1) {
07932 if (!res)
07933 res = ast_play_and_wait(chan, "vm-message");
07934 if (!res)
07935 res = ast_play_and_wait(chan, "vm-Olds");
07936 } else {
07937 if (!res)
07938 res = ast_play_and_wait(chan, "vm-messages");
07939 if (!res)
07940 res = ast_play_and_wait(chan, "vm-Old");
07941 }
07942 }
07943 return res;
07944 }
07945
07946
07947 static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
07948 {
07949
07950 int res;
07951 res = ast_play_and_wait(chan, "vm-youhave");
07952 if (!res) {
07953 if (vms->newmessages) {
07954 res = say_and_wait(chan, vms->newmessages, chan->language);
07955 if (!res)
07956 res = ast_play_and_wait(chan, "vm-INBOX");
07957 if (vms->oldmessages && !res)
07958 res = ast_play_and_wait(chan, "vm-and");
07959 else if (!res) {
07960 if ((vms->newmessages == 1))
07961 res = ast_play_and_wait(chan, "vm-message");
07962 else
07963 res = ast_play_and_wait(chan, "vm-messages");
07964 }
07965
07966 }
07967 if (!res && vms->oldmessages) {
07968 res = say_and_wait(chan, vms->oldmessages, chan->language);
07969 if (!res)
07970 res = ast_play_and_wait(chan, "vm-Old");
07971 if (!res) {
07972 if (vms->oldmessages == 1)
07973 res = ast_play_and_wait(chan, "vm-message");
07974 else
07975 res = ast_play_and_wait(chan, "vm-messages");
07976 }
07977 }
07978 if (!res) {
07979 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07980 res = ast_play_and_wait(chan, "vm-no");
07981 if (!res)
07982 res = ast_play_and_wait(chan, "vm-messages");
07983 }
07984 }
07985 }
07986 return res;
07987 }
07988
07989
07990 static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
07991 {
07992
07993 int res;
07994 res = ast_play_and_wait(chan, "vm-youhave");
07995 if (!res) {
07996 if (vms->newmessages) {
07997 res = say_and_wait(chan, vms->newmessages, chan->language);
07998 if (!res) {
07999 if (vms->newmessages == 1)
08000 res = ast_play_and_wait(chan, "vm-INBOXs");
08001 else
08002 res = ast_play_and_wait(chan, "vm-INBOX");
08003 }
08004 if (vms->oldmessages && !res)
08005 res = ast_play_and_wait(chan, "vm-and");
08006 else if (!res) {
08007 if ((vms->newmessages == 1))
08008 res = ast_play_and_wait(chan, "vm-message");
08009 else
08010 res = ast_play_and_wait(chan, "vm-messages");
08011 }
08012
08013 }
08014 if (!res && vms->oldmessages) {
08015 res = say_and_wait(chan, vms->oldmessages, chan->language);
08016 if (!res) {
08017 if (vms->oldmessages == 1)
08018 res = ast_play_and_wait(chan, "vm-Olds");
08019 else
08020 res = ast_play_and_wait(chan, "vm-Old");
08021 }
08022 if (!res) {
08023 if (vms->oldmessages == 1)
08024 res = ast_play_and_wait(chan, "vm-message");
08025 else
08026 res = ast_play_and_wait(chan, "vm-messages");
08027 }
08028 }
08029 if (!res) {
08030 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08031 res = ast_play_and_wait(chan, "vm-no");
08032 if (!res)
08033 res = ast_play_and_wait(chan, "vm-messages");
08034 }
08035 }
08036 }
08037 return res;
08038 }
08039
08040
08041 static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
08042 {
08043
08044 int res;
08045 res = ast_play_and_wait(chan, "vm-youhave");
08046 if (!res) {
08047 if (vms->newmessages) {
08048 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08049 if (!res) {
08050 if ((vms->newmessages == 1)) {
08051 res = ast_play_and_wait(chan, "vm-message");
08052 if (!res)
08053 res = ast_play_and_wait(chan, "vm-INBOXs");
08054 } else {
08055 res = ast_play_and_wait(chan, "vm-messages");
08056 if (!res)
08057 res = ast_play_and_wait(chan, "vm-INBOX");
08058 }
08059 }
08060 if (vms->oldmessages && !res)
08061 res = ast_play_and_wait(chan, "vm-and");
08062 }
08063 if (!res && vms->oldmessages) {
08064 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08065 if (!res) {
08066 if (vms->oldmessages == 1) {
08067 res = ast_play_and_wait(chan, "vm-message");
08068 if (!res)
08069 res = ast_play_and_wait(chan, "vm-Olds");
08070 } else {
08071 res = ast_play_and_wait(chan, "vm-messages");
08072 if (!res)
08073 res = ast_play_and_wait(chan, "vm-Old");
08074 }
08075 }
08076 }
08077 if (!res) {
08078 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08079 res = ast_play_and_wait(chan, "vm-no");
08080 if (!res)
08081 res = ast_play_and_wait(chan, "vm-messages");
08082 }
08083 }
08084 }
08085 return res;
08086 }
08087
08088
08089
08090
08091
08092
08093
08094
08095
08096
08097
08098
08099
08100
08101
08102
08103
08104 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08105 {
08106 int res;
08107 res = ast_play_and_wait(chan, "vm-youhave");
08108 if (!res) {
08109 if (vms->newmessages) {
08110 if (vms->newmessages == 1) {
08111 res = ast_play_and_wait(chan, "digits/jednu");
08112 } else {
08113 res = say_and_wait(chan, vms->newmessages, chan->language);
08114 }
08115 if (!res) {
08116 if ((vms->newmessages == 1))
08117 res = ast_play_and_wait(chan, "vm-novou");
08118 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08119 res = ast_play_and_wait(chan, "vm-nove");
08120 if (vms->newmessages > 4)
08121 res = ast_play_and_wait(chan, "vm-novych");
08122 }
08123 if (vms->oldmessages && !res)
08124 res = ast_play_and_wait(chan, "vm-and");
08125 else if (!res) {
08126 if ((vms->newmessages == 1))
08127 res = ast_play_and_wait(chan, "vm-zpravu");
08128 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08129 res = ast_play_and_wait(chan, "vm-zpravy");
08130 if (vms->newmessages > 4)
08131 res = ast_play_and_wait(chan, "vm-zprav");
08132 }
08133 }
08134 if (!res && vms->oldmessages) {
08135 res = say_and_wait(chan, vms->oldmessages, chan->language);
08136 if (!res) {
08137 if ((vms->oldmessages == 1))
08138 res = ast_play_and_wait(chan, "vm-starou");
08139 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08140 res = ast_play_and_wait(chan, "vm-stare");
08141 if (vms->oldmessages > 4)
08142 res = ast_play_and_wait(chan, "vm-starych");
08143 }
08144 if (!res) {
08145 if ((vms->oldmessages == 1))
08146 res = ast_play_and_wait(chan, "vm-zpravu");
08147 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08148 res = ast_play_and_wait(chan, "vm-zpravy");
08149 if (vms->oldmessages > 4)
08150 res = ast_play_and_wait(chan, "vm-zprav");
08151 }
08152 }
08153 if (!res) {
08154 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08155 res = ast_play_and_wait(chan, "vm-no");
08156 if (!res)
08157 res = ast_play_and_wait(chan, "vm-zpravy");
08158 }
08159 }
08160 }
08161 return res;
08162 }
08163
08164
08165 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08166 {
08167 int res;
08168
08169 res = ast_play_and_wait(chan, "vm-you");
08170
08171 if (!res && vms->newmessages) {
08172 res = ast_play_and_wait(chan, "vm-have");
08173 if (!res)
08174 res = say_and_wait(chan, vms->newmessages, chan->language);
08175 if (!res)
08176 res = ast_play_and_wait(chan, "vm-tong");
08177 if (!res)
08178 res = ast_play_and_wait(chan, "vm-INBOX");
08179 if (vms->oldmessages && !res)
08180 res = ast_play_and_wait(chan, "vm-and");
08181 else if (!res)
08182 res = ast_play_and_wait(chan, "vm-messages");
08183 }
08184 if (!res && vms->oldmessages) {
08185 res = ast_play_and_wait(chan, "vm-have");
08186 if (!res)
08187 res = say_and_wait(chan, vms->oldmessages, chan->language);
08188 if (!res)
08189 res = ast_play_and_wait(chan, "vm-tong");
08190 if (!res)
08191 res = ast_play_and_wait(chan, "vm-Old");
08192 if (!res)
08193 res = ast_play_and_wait(chan, "vm-messages");
08194 }
08195 if (!res && !vms->oldmessages && !vms->newmessages) {
08196 res = ast_play_and_wait(chan, "vm-haveno");
08197 if (!res)
08198 res = ast_play_and_wait(chan, "vm-messages");
08199 }
08200 return res;
08201 }
08202
08203 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
08204 {
08205 char prefile[256];
08206
08207
08208 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08209 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
08210 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08211 if (ast_fileexists(prefile, NULL, NULL) > 0) {
08212 ast_play_and_wait(chan, "vm-tempgreetactive");
08213 }
08214 DISPOSE(prefile, -1);
08215 }
08216
08217
08218 if (0) {
08219 } else if (!strncasecmp(chan->language, "cs", 2)) {
08220 return vm_intro_cs(chan, vms);
08221 } else if (!strncasecmp(chan->language, "cz", 2)) {
08222 static int deprecation_warning = 0;
08223 if (deprecation_warning++ % 10 == 0) {
08224 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
08225 }
08226 return vm_intro_cs(chan, vms);
08227 } else if (!strncasecmp(chan->language, "de", 2)) {
08228 return vm_intro_de(chan, vms);
08229 } else if (!strncasecmp(chan->language, "es", 2)) {
08230 return vm_intro_es(chan, vms);
08231 } else if (!strncasecmp(chan->language, "fr", 2)) {
08232 return vm_intro_fr(chan, vms);
08233 } else if (!strncasecmp(chan->language, "gr", 2)) {
08234 return vm_intro_gr(chan, vms);
08235 } else if (!strncasecmp(chan->language, "he", 2)) {
08236 return vm_intro_he(chan, vms);
08237 } else if (!strncasecmp(chan->language, "it", 2)) {
08238 return vm_intro_it(chan, vms);
08239 } else if (!strncasecmp(chan->language, "nl", 2)) {
08240 return vm_intro_nl(chan, vms);
08241 } else if (!strncasecmp(chan->language, "no", 2)) {
08242 return vm_intro_no(chan, vms);
08243 } else if (!strncasecmp(chan->language, "pl", 2)) {
08244 return vm_intro_pl(chan, vms);
08245 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
08246 return vm_intro_pt_BR(chan, vms);
08247 } else if (!strncasecmp(chan->language, "pt", 2)) {
08248 return vm_intro_pt(chan, vms);
08249 } else if (!strncasecmp(chan->language, "ru", 2)) {
08250 return vm_intro_multilang(chan, vms, "n");
08251 } else if (!strncasecmp(chan->language, "se", 2)) {
08252 return vm_intro_se(chan, vms);
08253 } else if (!strncasecmp(chan->language, "ua", 2)) {
08254 return vm_intro_multilang(chan, vms, "n");
08255 } else if (!strncasecmp(chan->language, "zh", 2)) {
08256 return vm_intro_zh(chan, vms);
08257 } else {
08258 return vm_intro_en(chan, vms);
08259 }
08260 }
08261
08262 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08263 {
08264 int res = 0;
08265
08266 while (!res) {
08267 if (vms->starting) {
08268 if (vms->lastmsg > -1) {
08269 if (skipadvanced)
08270 res = ast_play_and_wait(chan, "vm-onefor-full");
08271 else
08272 res = ast_play_and_wait(chan, "vm-onefor");
08273 if (!res)
08274 res = vm_play_folder_name(chan, vms->vmbox);
08275 }
08276 if (!res) {
08277 if (skipadvanced)
08278 res = ast_play_and_wait(chan, "vm-opts-full");
08279 else
08280 res = ast_play_and_wait(chan, "vm-opts");
08281 }
08282 } else {
08283
08284 if (skipadvanced) {
08285 res = ast_play_and_wait(chan, "vm-onefor-full");
08286 if (!res)
08287 res = vm_play_folder_name(chan, vms->vmbox);
08288 res = ast_play_and_wait(chan, "vm-opts-full");
08289 }
08290
08291
08292
08293
08294
08295
08296 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
08297 res = ast_play_and_wait(chan, "vm-prev");
08298 }
08299 if (!res && !skipadvanced)
08300 res = ast_play_and_wait(chan, "vm-advopts");
08301 if (!res)
08302 res = ast_play_and_wait(chan, "vm-repeat");
08303
08304
08305
08306
08307
08308
08309 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
08310 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
08311 res = ast_play_and_wait(chan, "vm-next");
08312 }
08313 if (!res) {
08314 if (!vms->deleted[vms->curmsg])
08315 res = ast_play_and_wait(chan, "vm-delete");
08316 else
08317 res = ast_play_and_wait(chan, "vm-undelete");
08318 if (!res)
08319 res = ast_play_and_wait(chan, "vm-toforward");
08320 if (!res)
08321 res = ast_play_and_wait(chan, "vm-savemessage");
08322 }
08323 }
08324 if (!res) {
08325 res = ast_play_and_wait(chan, "vm-helpexit");
08326 }
08327 if (!res)
08328 res = ast_waitfordigit(chan, 6000);
08329 if (!res) {
08330 vms->repeats++;
08331 if (vms->repeats > 2) {
08332 res = 't';
08333 }
08334 }
08335 }
08336 return res;
08337 }
08338
08339 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08340 {
08341 int res = 0;
08342
08343 while (!res) {
08344 if (vms->lastmsg > -1) {
08345 res = ast_play_and_wait(chan, "vm-listen");
08346 if (!res)
08347 res = vm_play_folder_name(chan, vms->vmbox);
08348 if (!res)
08349 res = ast_play_and_wait(chan, "press");
08350 if (!res)
08351 res = ast_play_and_wait(chan, "digits/1");
08352 }
08353 if (!res)
08354 res = ast_play_and_wait(chan, "vm-opts");
08355 if (!res) {
08356 vms->starting = 0;
08357 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08358 }
08359 }
08360 return res;
08361 }
08362
08363 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08364 {
08365 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
08366 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
08367 } else {
08368 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08369 }
08370 }
08371
08372
08373 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08374 {
08375 int cmd = 0;
08376 int duration = 0;
08377 int tries = 0;
08378 char newpassword[80] = "";
08379 char newpassword2[80] = "";
08380 char prefile[PATH_MAX] = "";
08381 unsigned char buf[256];
08382 int bytes=0;
08383
08384 if (ast_adsi_available(chan)) {
08385 bytes += adsi_logo(buf + bytes);
08386 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
08387 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
08388 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
08389 bytes += ast_adsi_voice_mode(buf + bytes, 0);
08390 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
08391 }
08392
08393
08394
08395 for (;;) {
08396 newpassword[1] = '\0';
08397 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
08398 if (cmd == '#')
08399 newpassword[0] = '\0';
08400 if (cmd < 0 || cmd == 't' || cmd == '#')
08401 return cmd;
08402 cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#");
08403 if (cmd < 0 || cmd == 't' || cmd == '#')
08404 return cmd;
08405 cmd = check_password(vmu, newpassword);
08406 if (cmd != 0) {
08407 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
08408 cmd = ast_play_and_wait(chan, vm_invalid_password);
08409 } else {
08410 newpassword2[1] = '\0';
08411 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
08412 if (cmd == '#')
08413 newpassword2[0] = '\0';
08414 if (cmd < 0 || cmd == 't' || cmd == '#')
08415 return cmd;
08416 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
08417 if (cmd < 0 || cmd == 't' || cmd == '#')
08418 return cmd;
08419 if (!strcmp(newpassword, newpassword2))
08420 break;
08421 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
08422 cmd = ast_play_and_wait(chan, vm_mismatch);
08423 }
08424 if (++tries == 3)
08425 return -1;
08426 if (cmd != 0) {
08427 cmd = ast_play_and_wait(chan, vm_pls_try_again);
08428 }
08429 }
08430 if (pwdchange & PWDCHANGE_INTERNAL)
08431 vm_change_password(vmu, newpassword);
08432 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
08433 vm_change_password_shell(vmu, newpassword);
08434
08435 ast_debug(1,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
08436 cmd = ast_play_and_wait(chan, vm_passchanged);
08437
08438
08439 if (ast_test_flag(vmu, VM_FORCENAME)) {
08440 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
08441 if (ast_fileexists(prefile, NULL, NULL) < 1) {
08442 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08443 if (cmd < 0 || cmd == 't' || cmd == '#')
08444 return cmd;
08445 }
08446 }
08447
08448
08449 if (ast_test_flag(vmu, VM_FORCEGREET)) {
08450 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
08451 if (ast_fileexists(prefile, NULL, NULL) < 1) {
08452 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08453 if (cmd < 0 || cmd == 't' || cmd == '#')
08454 return cmd;
08455 }
08456
08457 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
08458 if (ast_fileexists(prefile, NULL, NULL) < 1) {
08459 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08460 if (cmd < 0 || cmd == 't' || cmd == '#')
08461 return cmd;
08462 }
08463 }
08464
08465 return cmd;
08466 }
08467
08468 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08469 {
08470 int cmd = 0;
08471 int retries = 0;
08472 int duration = 0;
08473 char newpassword[80] = "";
08474 char newpassword2[80] = "";
08475 char prefile[PATH_MAX] = "";
08476 unsigned char buf[256];
08477 int bytes=0;
08478
08479 if (ast_adsi_available(chan)) {
08480 bytes += adsi_logo(buf + bytes);
08481 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
08482 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
08483 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
08484 bytes += ast_adsi_voice_mode(buf + bytes, 0);
08485 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
08486 }
08487 while ((cmd >= 0) && (cmd != 't')) {
08488 if (cmd)
08489 retries = 0;
08490 switch (cmd) {
08491 case '1':
08492 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
08493 cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08494 break;
08495 case '2':
08496 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
08497 cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08498 break;
08499 case '3':
08500 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
08501 cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08502 break;
08503 case '4':
08504 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
08505 break;
08506 case '5':
08507 if (vmu->password[0] == '-') {
08508 cmd = ast_play_and_wait(chan, "vm-no");
08509 break;
08510 }
08511 newpassword[1] = '\0';
08512 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
08513 if (cmd == '#')
08514 newpassword[0] = '\0';
08515 else {
08516 if (cmd < 0)
08517 break;
08518 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
08519 break;
08520 }
08521 }
08522 cmd = check_password(vmu, newpassword);
08523 if (cmd != 0) {
08524 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
08525 cmd = ast_play_and_wait(chan, vm_invalid_password);
08526 if (!cmd) {
08527 cmd = ast_play_and_wait(chan, vm_pls_try_again);
08528 }
08529 break;
08530 }
08531 newpassword2[1] = '\0';
08532 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
08533 if (cmd == '#')
08534 newpassword2[0] = '\0';
08535 else {
08536 if (cmd < 0)
08537 break;
08538
08539 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#")) < 0) {
08540 break;
08541 }
08542 }
08543 if (strcmp(newpassword, newpassword2)) {
08544 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
08545 cmd = ast_play_and_wait(chan, vm_mismatch);
08546 if (!cmd) {
08547 cmd = ast_play_and_wait(chan, vm_pls_try_again);
08548 }
08549 break;
08550 }
08551 if (pwdchange & PWDCHANGE_INTERNAL)
08552 vm_change_password(vmu, newpassword);
08553 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
08554 vm_change_password_shell(vmu, newpassword);
08555
08556 ast_debug(1,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
08557 cmd = ast_play_and_wait(chan, vm_passchanged);
08558 break;
08559 case '*':
08560 cmd = 't';
08561 break;
08562 default:
08563 cmd = 0;
08564 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08565 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08566 if (ast_fileexists(prefile, NULL, NULL)) {
08567 cmd = ast_play_and_wait(chan, "vm-tmpexists");
08568 }
08569 DISPOSE(prefile, -1);
08570 if (!cmd) {
08571 cmd = ast_play_and_wait(chan, "vm-options");
08572 }
08573 if (!cmd) {
08574 cmd = ast_waitfordigit(chan,6000);
08575 }
08576 if (!cmd) {
08577 retries++;
08578 }
08579 if (retries > 3) {
08580 cmd = 't';
08581 }
08582 }
08583 }
08584 if (cmd == 't')
08585 cmd = 0;
08586 return cmd;
08587 }
08588
08589
08590
08591
08592
08593
08594
08595
08596
08597
08598
08599
08600
08601
08602
08603
08604
08605 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08606 {
08607 int cmd = 0;
08608 int retries = 0;
08609 int duration = 0;
08610 char prefile[PATH_MAX] = "";
08611 unsigned char buf[256];
08612 int bytes = 0;
08613
08614 if (ast_adsi_available(chan)) {
08615 bytes += adsi_logo(buf + bytes);
08616 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
08617 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
08618 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
08619 bytes += ast_adsi_voice_mode(buf + bytes, 0);
08620 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
08621 }
08622
08623 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08624 while ((cmd >= 0) && (cmd != 't')) {
08625 if (cmd)
08626 retries = 0;
08627 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08628 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
08629 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08630 cmd = 't';
08631 } else {
08632 switch (cmd) {
08633 case '1':
08634 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08635 break;
08636 case '2':
08637 DELETE(prefile, -1, prefile, vmu);
08638 ast_play_and_wait(chan, "vm-tempremoved");
08639 cmd = 't';
08640 break;
08641 case '*':
08642 cmd = 't';
08643 break;
08644 default:
08645 cmd = ast_play_and_wait(chan,
08646 ast_fileexists(prefile, NULL, NULL) > 0 ?
08647 "vm-tempgreeting2" : "vm-tempgreeting");
08648 if (!cmd)
08649 cmd = ast_waitfordigit(chan,6000);
08650 if (!cmd)
08651 retries++;
08652 if (retries > 3)
08653 cmd = 't';
08654 }
08655 }
08656 DISPOSE(prefile, -1);
08657 }
08658 if (cmd == 't')
08659 cmd = 0;
08660 return cmd;
08661 }
08662
08663
08664
08665
08666
08667
08668
08669
08670
08671 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08672 {
08673 int cmd=0;
08674
08675 if (vms->lastmsg > -1) {
08676 cmd = play_message(chan, vmu, vms);
08677 } else {
08678 cmd = ast_play_and_wait(chan, "vm-youhaveno");
08679 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
08680 if (!cmd) {
08681 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
08682 cmd = ast_play_and_wait(chan, vms->fn);
08683 }
08684 if (!cmd)
08685 cmd = ast_play_and_wait(chan, "vm-messages");
08686 } else {
08687 if (!cmd)
08688 cmd = ast_play_and_wait(chan, "vm-messages");
08689 if (!cmd) {
08690 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08691 cmd = ast_play_and_wait(chan, vms->fn);
08692 }
08693 }
08694 }
08695 return cmd;
08696 }
08697
08698
08699 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08700 {
08701 int cmd = 0;
08702
08703 if (vms->lastmsg > -1) {
08704 cmd = play_message(chan, vmu, vms);
08705 } else {
08706 if (!strcasecmp(vms->fn, "INBOX")) {
08707 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
08708 } else {
08709 cmd = ast_play_and_wait(chan, "vm-nomessages");
08710 }
08711 }
08712 return cmd;
08713 }
08714
08715
08716
08717
08718
08719
08720
08721
08722
08723 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08724 {
08725 int cmd=0;
08726
08727 if (vms->lastmsg > -1) {
08728 cmd = play_message(chan, vmu, vms);
08729 } else {
08730 cmd = ast_play_and_wait(chan, "vm-youhave");
08731 if (!cmd)
08732 cmd = ast_play_and_wait(chan, "vm-no");
08733 if (!cmd) {
08734 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08735 cmd = ast_play_and_wait(chan, vms->fn);
08736 }
08737 if (!cmd)
08738 cmd = ast_play_and_wait(chan, "vm-messages");
08739 }
08740 return cmd;
08741 }
08742
08743
08744
08745
08746
08747
08748
08749
08750
08751 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08752 {
08753 int cmd=0;
08754
08755 if (vms->lastmsg > -1) {
08756 cmd = play_message(chan, vmu, vms);
08757 } else {
08758 cmd = ast_play_and_wait(chan, "vm-no");
08759 if (!cmd)
08760 cmd = ast_play_and_wait(chan, "vm-message");
08761 if (!cmd) {
08762 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08763 cmd = ast_play_and_wait(chan, vms->fn);
08764 }
08765 }
08766 return cmd;
08767 }
08768
08769
08770
08771
08772
08773
08774
08775
08776
08777 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08778 {
08779 int cmd=0;
08780
08781 if (vms->lastmsg > -1) {
08782 cmd = play_message(chan, vmu, vms);
08783 } else {
08784 cmd = ast_play_and_wait(chan, "vm-youhaveno");
08785 if (!cmd)
08786 cmd = ast_play_and_wait(chan, "vm-messages");
08787 if (!cmd) {
08788 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08789 cmd = ast_play_and_wait(chan, vms->fn);
08790 }
08791 }
08792 return cmd;
08793 }
08794
08795
08796
08797
08798
08799
08800
08801
08802
08803 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08804 {
08805 int cmd=0;
08806
08807 if (vms->lastmsg > -1) {
08808 cmd = play_message(chan, vmu, vms);
08809 } else {
08810 cmd = ast_play_and_wait(chan, "vm-no");
08811 if (!cmd) {
08812 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08813 cmd = ast_play_and_wait(chan, vms->fn);
08814 }
08815 if (!cmd)
08816 cmd = ast_play_and_wait(chan, "vm-messages");
08817 }
08818 return cmd;
08819 }
08820
08821
08822
08823
08824
08825
08826
08827
08828
08829 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08830 {
08831 int cmd=0;
08832
08833 if (vms->lastmsg > -1) {
08834 cmd = play_message(chan, vmu, vms);
08835 } else {
08836 cmd = ast_play_and_wait(chan, "vm-you");
08837 if (!cmd)
08838 cmd = ast_play_and_wait(chan, "vm-haveno");
08839 if (!cmd)
08840 cmd = ast_play_and_wait(chan, "vm-messages");
08841 if (!cmd) {
08842 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08843 cmd = ast_play_and_wait(chan, vms->fn);
08844 }
08845 }
08846 return cmd;
08847 }
08848
08849
08850
08851
08852
08853
08854
08855
08856
08857
08858
08859
08860 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08861 {
08862 if (!strncasecmp(chan->language, "es", 2)) {
08863 return vm_browse_messages_es(chan, vms, vmu);
08864 } else if (!strncasecmp(chan->language, "gr", 2)) {
08865 return vm_browse_messages_gr(chan, vms, vmu);
08866 } else if (!strncasecmp(chan->language, "he", 2)) {
08867 return vm_browse_messages_he(chan, vms, vmu);
08868 } else if (!strncasecmp(chan->language, "it", 2)) {
08869 return vm_browse_messages_it(chan, vms, vmu);
08870 } else if (!strncasecmp(chan->language, "pt", 2)) {
08871 return vm_browse_messages_pt(chan, vms, vmu);
08872 } else if (!strncasecmp(chan->language, "zh", 2)) {
08873 return vm_browse_messages_zh(chan, vms, vmu);
08874 } else {
08875 return vm_browse_messages_en(chan, vms, vmu);
08876 }
08877 }
08878
08879 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
08880 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
08881 int skipuser, int max_logins, int silent)
08882 {
08883 int useadsi=0, valid=0, logretries=0;
08884 char password[AST_MAX_EXTENSION]="", *passptr;
08885 struct ast_vm_user vmus, *vmu = NULL;
08886
08887
08888 adsi_begin(chan, &useadsi);
08889 if (!skipuser && useadsi)
08890 adsi_login(chan);
08891 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
08892 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
08893 return -1;
08894 }
08895
08896
08897
08898 while (!valid && (logretries < max_logins)) {
08899
08900 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
08901 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
08902 return -1;
08903 }
08904 if (ast_strlen_zero(mailbox)) {
08905 if (chan->cid.cid_num) {
08906 ast_copy_string(mailbox, chan->cid.cid_num, mailbox_size);
08907 } else {
08908 ast_verb(3,"Username not entered\n");
08909 return -1;
08910 }
08911 }
08912 if (useadsi)
08913 adsi_password(chan);
08914
08915 if (!ast_strlen_zero(prefix)) {
08916 char fullusername[80] = "";
08917 ast_copy_string(fullusername, prefix, sizeof(fullusername));
08918 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
08919 ast_copy_string(mailbox, fullusername, mailbox_size);
08920 }
08921
08922 ast_debug(1, "Before find user for mailbox %s\n",mailbox);
08923 vmu = find_user(&vmus, context, mailbox);
08924 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
08925
08926 password[0] = '\0';
08927 } else {
08928 if (ast_streamfile(chan, vm_password, chan->language)) {
08929 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
08930 return -1;
08931 }
08932 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
08933 ast_log(AST_LOG_WARNING, "Unable to read password\n");
08934 return -1;
08935 }
08936 }
08937
08938 if (vmu) {
08939 passptr = vmu->password;
08940 if (passptr[0] == '-') passptr++;
08941 }
08942 if (vmu && !strcmp(passptr, password))
08943 valid++;
08944 else {
08945 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
08946 if (!ast_strlen_zero(prefix))
08947 mailbox[0] = '\0';
08948 }
08949 logretries++;
08950 if (!valid) {
08951 if (skipuser || logretries >= max_logins) {
08952 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
08953 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
08954 return -1;
08955 }
08956 } else {
08957 if (useadsi)
08958 adsi_login(chan);
08959 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
08960 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
08961 return -1;
08962 }
08963 }
08964 if (ast_waitstream(chan, ""))
08965 return -1;
08966 }
08967 }
08968 if (!valid && (logretries >= max_logins)) {
08969 ast_stopstream(chan);
08970 ast_play_and_wait(chan, "vm-goodbye");
08971 return -1;
08972 }
08973 if (vmu && !skipuser) {
08974 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
08975 }
08976 return 0;
08977 }
08978
08979 static int vm_execmain(struct ast_channel *chan, void *data)
08980 {
08981
08982
08983
08984 int res=-1;
08985 int cmd=0;
08986 int valid = 0;
08987 char prefixstr[80] ="";
08988 char ext_context[256]="";
08989 int box;
08990 int useadsi = 0;
08991 int skipuser = 0;
08992 struct vm_state vms;
08993 struct ast_vm_user *vmu = NULL, vmus;
08994 char *context=NULL;
08995 int silentexit = 0;
08996 struct ast_flags flags = { 0 };
08997 signed char record_gain = 0;
08998 int play_auto = 0;
08999 int play_folder = 0;
09000 int in_urgent = 0;
09001 #ifdef IMAP_STORAGE
09002 int deleted = 0;
09003 #endif
09004
09005
09006 memset(&vms, 0, sizeof(vms));
09007
09008 vms.lastmsg = -1;
09009
09010 memset(&vmus, 0, sizeof(vmus));
09011
09012 if (chan->_state != AST_STATE_UP) {
09013 ast_debug(1, "Before ast_answer\n");
09014 ast_answer(chan);
09015 }
09016
09017 if (!ast_strlen_zero(data)) {
09018 char *opts[OPT_ARG_ARRAY_SIZE];
09019 char *parse;
09020 AST_DECLARE_APP_ARGS(args,
09021 AST_APP_ARG(argv0);
09022 AST_APP_ARG(argv1);
09023 );
09024
09025 parse = ast_strdupa(data);
09026
09027 AST_STANDARD_APP_ARGS(args, parse);
09028
09029 if (args.argc == 2) {
09030 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09031 return -1;
09032 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09033 int gain;
09034 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09035 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09036 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09037 return -1;
09038 } else {
09039 record_gain = (signed char) gain;
09040 }
09041 } else {
09042 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09043 }
09044 }
09045 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09046 play_auto = 1;
09047 if (opts[OPT_ARG_PLAYFOLDER]) {
09048 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09049 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for folder autoplay option\n", opts[OPT_ARG_PLAYFOLDER]);
09050 }
09051 } else {
09052 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09053 }
09054 if ( play_folder > 9 || play_folder < 0) {
09055 ast_log(AST_LOG_WARNING, "Invalid value '%d' provided for folder autoplay option\n", play_folder);
09056 play_folder = 0;
09057 }
09058 }
09059 } else {
09060
09061 while (*(args.argv0)) {
09062 if (*(args.argv0) == 's')
09063 ast_set_flag(&flags, OPT_SILENT);
09064 else if (*(args.argv0) == 'p')
09065 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09066 else
09067 break;
09068 (args.argv0)++;
09069 }
09070
09071 }
09072
09073 valid = ast_test_flag(&flags, OPT_SILENT);
09074
09075 if ((context = strchr(args.argv0, '@')))
09076 *context++ = '\0';
09077
09078 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09079 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09080 else
09081 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09082
09083 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09084 skipuser++;
09085 else
09086 valid = 0;
09087 }
09088
09089 if (!valid)
09090 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09091
09092 ast_debug(1, "After vm_authenticate\n");
09093 if (!res) {
09094 valid = 1;
09095 if (!skipuser)
09096 vmu = &vmus;
09097 } else {
09098 res = 0;
09099 }
09100
09101
09102 adsi_begin(chan, &useadsi);
09103
09104 if (!valid) {
09105 goto out;
09106 }
09107
09108 #ifdef IMAP_STORAGE
09109 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
09110 pthread_setspecific(ts_vmstate.key, &vms);
09111
09112 vms.interactive = 1;
09113 vms.updated = 1;
09114 if (vmu)
09115 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
09116 vmstate_insert(&vms);
09117 init_vm_state(&vms);
09118 #endif
09119 if (!(vms.deleted = ast_calloc(vmu->maxmsg, sizeof(int)))) {
09120 ast_log(AST_LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
09121 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09122 return -1;
09123 }
09124 if (!(vms.heard = ast_calloc(vmu->maxmsg, sizeof(int)))) {
09125 ast_log(AST_LOG_ERROR, "Could not allocate memory for heard message storage!\n");
09126 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09127 return -1;
09128 }
09129
09130
09131 if (!ast_strlen_zero(vmu->language))
09132 ast_string_field_set(chan, language, vmu->language);
09133
09134
09135 ast_debug(1, "Before open_mailbox\n");
09136 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09137 if (res == ERROR_LOCK_PATH)
09138 goto out;
09139 vms.oldmessages = vms.lastmsg + 1;
09140 ast_debug(1, "Number of old messages: %d\n",vms.oldmessages);
09141
09142 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09143 if (res == ERROR_LOCK_PATH)
09144 goto out;
09145 vms.newmessages = vms.lastmsg + 1;
09146 ast_debug(1, "Number of new messages: %d\n",vms.newmessages);
09147
09148 in_urgent = 1;
09149 res = open_mailbox(&vms, vmu, 11);
09150 if (res == ERROR_LOCK_PATH)
09151 goto out;
09152 vms.urgentmessages = vms.lastmsg + 1;
09153 ast_debug(1, "Number of urgent messages: %d\n",vms.urgentmessages);
09154
09155
09156 if (play_auto) {
09157 if (vms.urgentmessages) {
09158 in_urgent = 1;
09159 res = open_mailbox(&vms, vmu, 11);
09160 } else {
09161 in_urgent = 0;
09162 res = open_mailbox(&vms, vmu, play_folder);
09163 }
09164 if (res == ERROR_LOCK_PATH)
09165 goto out;
09166
09167
09168 if (vms.lastmsg == -1) {
09169 in_urgent = 0;
09170 cmd = vm_browse_messages(chan, &vms, vmu);
09171 res = 0;
09172 goto out;
09173 }
09174 } else {
09175 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
09176
09177 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09178 in_urgent = 0;
09179 play_folder = 1;
09180 if (res == ERROR_LOCK_PATH)
09181 goto out;
09182 } else if (!vms.urgentmessages && vms.newmessages) {
09183
09184 in_urgent = 0;
09185 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09186 if (res == ERROR_LOCK_PATH)
09187 goto out;
09188 }
09189 }
09190
09191 if (useadsi)
09192 adsi_status(chan, &vms);
09193 res = 0;
09194
09195
09196 if (!strcasecmp(vmu->mailbox, vmu->password) &&
09197 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
09198 if (ast_play_and_wait(chan, "vm-newuser") == -1)
09199 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
09200 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
09201 if ((cmd == 't') || (cmd == '#')) {
09202
09203 res = 0;
09204 goto out;
09205 } else if (cmd < 0) {
09206
09207 res = -1;
09208 goto out;
09209 }
09210 }
09211 #ifdef IMAP_STORAGE
09212 ast_debug(3, "Checking quotas: comparing %u to %u\n",vms.quota_usage,vms.quota_limit);
09213 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
09214 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
09215 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09216 }
09217 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
09218 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
09219 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
09220 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09221 }
09222 #endif
09223 if (play_auto) {
09224 cmd = '1';
09225 } else {
09226 cmd = vm_intro(chan, vmu, &vms);
09227 }
09228
09229 vms.repeats = 0;
09230 vms.starting = 1;
09231 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09232
09233 switch (cmd) {
09234 case '1':
09235 vms.curmsg = 0;
09236
09237 case '5':
09238 cmd = vm_browse_messages(chan, &vms, vmu);
09239 break;
09240 case '2':
09241 if (useadsi)
09242 adsi_folders(chan, 0, "Change to folder...");
09243 cmd = get_folder2(chan, "vm-changeto", 0);
09244 if (cmd == '#') {
09245 cmd = 0;
09246 } else if (cmd > 0) {
09247 cmd = cmd - '0';
09248 res = close_mailbox(&vms, vmu);
09249 if (res == ERROR_LOCK_PATH)
09250 goto out;
09251
09252 if (cmd != 11) in_urgent = 0;
09253 res = open_mailbox(&vms, vmu, cmd);
09254 if (res == ERROR_LOCK_PATH)
09255 goto out;
09256 play_folder = cmd;
09257 cmd = 0;
09258 }
09259 if (useadsi)
09260 adsi_status2(chan, &vms);
09261
09262 if (!cmd)
09263 cmd = vm_play_folder_name(chan, vms.vmbox);
09264
09265 vms.starting = 1;
09266 break;
09267 case '3':
09268 cmd = 0;
09269 vms.repeats = 0;
09270 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09271 switch (cmd) {
09272 case '1':
09273 if (vms.lastmsg > -1 && !vms.starting) {
09274 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
09275 if (cmd == ERROR_LOCK_PATH) {
09276 res = cmd;
09277 goto out;
09278 }
09279 } else
09280 cmd = ast_play_and_wait(chan, "vm-sorry");
09281 cmd = 't';
09282 break;
09283 case '2':
09284 if (!vms.starting)
09285 ast_verb(3, "Callback Requested\n");
09286 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
09287 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
09288 if (cmd == 9) {
09289 silentexit = 1;
09290 goto out;
09291 } else if (cmd == ERROR_LOCK_PATH) {
09292 res = cmd;
09293 goto out;
09294 }
09295 } else
09296 cmd = ast_play_and_wait(chan, "vm-sorry");
09297 cmd = 't';
09298 break;
09299 case '3':
09300 if (vms.lastmsg > -1 && !vms.starting) {
09301 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
09302 if (cmd == ERROR_LOCK_PATH) {
09303 res = cmd;
09304 goto out;
09305 }
09306 } else
09307 cmd = ast_play_and_wait(chan, "vm-sorry");
09308 cmd = 't';
09309 break;
09310 case '4':
09311 if (!ast_strlen_zero(vmu->dialout)) {
09312 cmd = dialout(chan, vmu, NULL, vmu->dialout);
09313 if (cmd == 9) {
09314 silentexit = 1;
09315 goto out;
09316 }
09317 } else
09318 cmd = ast_play_and_wait(chan, "vm-sorry");
09319 cmd = 't';
09320 break;
09321
09322 case '5':
09323 if (ast_test_flag(vmu, VM_SVMAIL)) {
09324 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
09325 if (cmd == ERROR_LOCK_PATH) {
09326 res = cmd;
09327 ast_log(AST_LOG_WARNING, "forward_message failed to lock path.\n");
09328 goto out;
09329 }
09330 } else
09331 cmd = ast_play_and_wait(chan,"vm-sorry");
09332 cmd='t';
09333 break;
09334
09335 case '*':
09336 cmd = 't';
09337 break;
09338
09339 default:
09340 cmd = 0;
09341 if (!vms.starting) {
09342 cmd = ast_play_and_wait(chan, "vm-toreply");
09343 }
09344 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
09345 cmd = ast_play_and_wait(chan, "vm-tocallback");
09346 }
09347 if (!cmd && !vms.starting) {
09348 cmd = ast_play_and_wait(chan, "vm-tohearenv");
09349 }
09350 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
09351 cmd = ast_play_and_wait(chan, "vm-tomakecall");
09352 }
09353 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
09354 cmd=ast_play_and_wait(chan, "vm-leavemsg");
09355 if (!cmd)
09356 cmd = ast_play_and_wait(chan, "vm-starmain");
09357 if (!cmd)
09358 cmd = ast_waitfordigit(chan,6000);
09359 if (!cmd)
09360 vms.repeats++;
09361 if (vms.repeats > 3)
09362 cmd = 't';
09363 }
09364 }
09365 if (cmd == 't') {
09366 cmd = 0;
09367 vms.repeats = 0;
09368 }
09369 break;
09370 case '4':
09371 if (vms.curmsg > 0) {
09372 vms.curmsg--;
09373 cmd = play_message(chan, vmu, &vms);
09374 } else {
09375
09376
09377
09378
09379 if (in_urgent == 0 && vms.urgentmessages > 0) {
09380
09381 in_urgent = 1;
09382 res = close_mailbox(&vms, vmu);
09383 if (res == ERROR_LOCK_PATH)
09384 goto out;
09385 res = open_mailbox(&vms, vmu, 11);
09386 if (res == ERROR_LOCK_PATH)
09387 goto out;
09388 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n",vms.lastmsg + 1);
09389 vms.curmsg = vms.lastmsg;
09390 if (vms.lastmsg < 0)
09391 cmd = ast_play_and_wait(chan, "vm-nomore");
09392 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09393 vms.curmsg = vms.lastmsg;
09394 cmd = play_message(chan, vmu, &vms);
09395 } else {
09396 cmd = ast_play_and_wait(chan, "vm-nomore");
09397 }
09398 }
09399 break;
09400 case '6':
09401 if (vms.curmsg < vms.lastmsg) {
09402 vms.curmsg++;
09403 cmd = play_message(chan, vmu, &vms);
09404 } else {
09405 if (in_urgent && vms.newmessages > 0) {
09406
09407
09408
09409
09410 in_urgent = 0;
09411 res = close_mailbox(&vms, vmu);
09412 if (res == ERROR_LOCK_PATH)
09413 goto out;
09414 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09415 if (res == ERROR_LOCK_PATH)
09416 goto out;
09417 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09418 vms.curmsg = -1;
09419 if (vms.lastmsg < 0) {
09420 cmd = ast_play_and_wait(chan, "vm-nomore");
09421 }
09422 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09423 vms.curmsg = 0;
09424 cmd = play_message(chan, vmu, &vms);
09425 } else {
09426 cmd = ast_play_and_wait(chan, "vm-nomore");
09427 }
09428 }
09429 break;
09430 case '7':
09431 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
09432 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
09433 if (useadsi)
09434 adsi_delete(chan, &vms);
09435 if (vms.deleted[vms.curmsg]) {
09436 if (play_folder == 0) {
09437 if (in_urgent) {
09438 vms.urgentmessages--;
09439 } else {
09440 vms.newmessages--;
09441 }
09442 }
09443 else if (play_folder == 1)
09444 vms.oldmessages--;
09445 cmd = ast_play_and_wait(chan, "vm-deleted");
09446 } else {
09447 if (play_folder == 0) {
09448 if (in_urgent) {
09449 vms.urgentmessages++;
09450 } else {
09451 vms.newmessages++;
09452 }
09453 }
09454 else if (play_folder == 1)
09455 vms.oldmessages++;
09456 cmd = ast_play_and_wait(chan, "vm-undeleted");
09457 }
09458 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
09459 if (vms.curmsg < vms.lastmsg) {
09460 vms.curmsg++;
09461 cmd = play_message(chan, vmu, &vms);
09462 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09463 vms.curmsg = 0;
09464 cmd = play_message(chan, vmu, &vms);
09465 } else {
09466
09467
09468
09469
09470 if (in_urgent == 1) {
09471
09472 in_urgent = 0;
09473 res = close_mailbox(&vms, vmu);
09474 if (res == ERROR_LOCK_PATH)
09475 goto out;
09476 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09477 if (res == ERROR_LOCK_PATH)
09478 goto out;
09479 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09480 vms.curmsg = -1;
09481 if (vms.lastmsg < 0)
09482 cmd = ast_play_and_wait(chan, "vm-nomore");
09483 } else {
09484 cmd = ast_play_and_wait(chan, "vm-nomore");
09485 }
09486 }
09487 }
09488 } else
09489 cmd = 0;
09490 #ifdef IMAP_STORAGE
09491 deleted = 1;
09492 #endif
09493 break;
09494
09495 case '8':
09496 if (vms.lastmsg > -1) {
09497 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
09498 if (cmd == ERROR_LOCK_PATH) {
09499 res = cmd;
09500 goto out;
09501 }
09502 } else {
09503
09504
09505
09506
09507 if (in_urgent == 1 && vms.newmessages > 0) {
09508
09509 in_urgent = 0;
09510 res = close_mailbox(&vms, vmu);
09511 if (res == ERROR_LOCK_PATH)
09512 goto out;
09513 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09514 if (res == ERROR_LOCK_PATH)
09515 goto out;
09516 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09517 vms.curmsg = -1;
09518 if (vms.lastmsg < 0)
09519 cmd = ast_play_and_wait(chan, "vm-nomore");
09520 } else {
09521 cmd = ast_play_and_wait(chan, "vm-nomore");
09522 }
09523 }
09524 break;
09525 case '9':
09526 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
09527
09528 cmd = 0;
09529 break;
09530 }
09531 if (useadsi)
09532 adsi_folders(chan, 1, "Save to folder...");
09533 cmd = get_folder2(chan, "vm-savefolder", 1);
09534 box = 0;
09535 if (cmd == '#') {
09536 cmd = 0;
09537 break;
09538 } else if (cmd > 0) {
09539 box = cmd = cmd - '0';
09540 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
09541 if (cmd == ERROR_LOCK_PATH) {
09542 res = cmd;
09543 goto out;
09544 #ifndef IMAP_STORAGE
09545 } else if (!cmd) {
09546 vms.deleted[vms.curmsg] = 1;
09547 #endif
09548 } else {
09549 vms.deleted[vms.curmsg] = 0;
09550 vms.heard[vms.curmsg] = 0;
09551 }
09552 }
09553 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
09554 if (useadsi)
09555 adsi_message(chan, &vms);
09556 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
09557 if (!cmd) {
09558 cmd = ast_play_and_wait(chan, "vm-message");
09559 if (!cmd)
09560 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
09561 if (!cmd)
09562 cmd = ast_play_and_wait(chan, "vm-savedto");
09563 if (!cmd)
09564 cmd = vm_play_folder_name(chan, vms.fn);
09565 } else {
09566 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09567 }
09568 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
09569 if (vms.curmsg < vms.lastmsg) {
09570 vms.curmsg++;
09571 cmd = play_message(chan, vmu, &vms);
09572 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09573 vms.curmsg = 0;
09574 cmd = play_message(chan, vmu, &vms);
09575 } else {
09576
09577
09578
09579
09580 if (in_urgent == 1 && vms.newmessages > 0) {
09581
09582 in_urgent = 0;
09583 res = close_mailbox(&vms, vmu);
09584 if (res == ERROR_LOCK_PATH)
09585 goto out;
09586 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09587 if (res == ERROR_LOCK_PATH)
09588 goto out;
09589 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09590 vms.curmsg = -1;
09591 if (vms.lastmsg < 0)
09592 cmd = ast_play_and_wait(chan, "vm-nomore");
09593 } else {
09594 cmd = ast_play_and_wait(chan, "vm-nomore");
09595 }
09596 }
09597 }
09598 break;
09599 case '*':
09600 if (!vms.starting) {
09601 cmd = ast_play_and_wait(chan, "vm-onefor");
09602 if (!strncasecmp(chan->language, "he", 2)) {
09603 cmd = ast_play_and_wait(chan, "vm-for");
09604 }
09605 if (!cmd)
09606 cmd = vm_play_folder_name(chan, vms.vmbox);
09607 if (!cmd)
09608 cmd = ast_play_and_wait(chan, "vm-opts");
09609 if (!cmd)
09610 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
09611 } else
09612 cmd = 0;
09613 break;
09614 case '0':
09615 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
09616 if (useadsi)
09617 adsi_status(chan, &vms);
09618 break;
09619 default:
09620 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
09621 break;
09622 }
09623 }
09624 if ((cmd == 't') || (cmd == '#')) {
09625
09626 res = 0;
09627 } else {
09628
09629 res = -1;
09630 }
09631
09632 out:
09633 if (res > -1) {
09634 ast_stopstream(chan);
09635 adsi_goodbye(chan);
09636 if (valid) {
09637 if (silentexit)
09638 res = ast_play_and_wait(chan, "vm-dialout");
09639 else
09640 res = ast_play_and_wait(chan, "vm-goodbye");
09641 if (res > 0)
09642 res = 0;
09643 }
09644 if (useadsi)
09645 ast_adsi_unload_session(chan);
09646 }
09647 if (vmu)
09648 close_mailbox(&vms, vmu);
09649 if (valid) {
09650 int new = 0, old = 0, urgent = 0;
09651 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
09652 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
09653
09654 run_externnotify(vmu->context, vmu->mailbox, NULL);
09655 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
09656 queue_mwi_event(ext_context, urgent, new, old);
09657 }
09658 #ifdef IMAP_STORAGE
09659
09660 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted,expungeonhangup);
09661 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
09662 ast_mutex_lock(&vms.lock);
09663 #ifdef HAVE_IMAP_TK2006
09664 if (LEVELUIDPLUS (vms.mailstream)) {
09665 mail_expunge_full(vms.mailstream,NIL,EX_UID);
09666 } else
09667 #endif
09668 mail_expunge(vms.mailstream);
09669 ast_mutex_unlock(&vms.lock);
09670 }
09671
09672
09673 if (vmu) {
09674 vmstate_delete(&vms);
09675 }
09676 #endif
09677 if (vmu)
09678 free_user(vmu);
09679 if (vms.deleted)
09680 ast_free(vms.deleted);
09681 if (vms.heard)
09682 ast_free(vms.heard);
09683
09684 #ifdef IMAP_STORAGE
09685 pthread_setspecific(ts_vmstate.key, NULL);
09686 #endif
09687 return res;
09688 }
09689
09690 static int vm_exec(struct ast_channel *chan, void *data)
09691 {
09692 int res = 0;
09693 char *tmp;
09694 struct leave_vm_options leave_options;
09695 struct ast_flags flags = { 0 };
09696 char *opts[OPT_ARG_ARRAY_SIZE];
09697 AST_DECLARE_APP_ARGS(args,
09698 AST_APP_ARG(argv0);
09699 AST_APP_ARG(argv1);
09700 );
09701
09702 memset(&leave_options, 0, sizeof(leave_options));
09703
09704 if (chan->_state != AST_STATE_UP)
09705 ast_answer(chan);
09706
09707 if (!ast_strlen_zero(data)) {
09708 tmp = ast_strdupa(data);
09709 AST_STANDARD_APP_ARGS(args, tmp);
09710 if (args.argc == 2) {
09711 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09712 return -1;
09713 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
09714 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09715 int gain;
09716
09717 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09718 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09719 return -1;
09720 } else {
09721 leave_options.record_gain = (signed char) gain;
09722 }
09723 }
09724 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
09725 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
09726 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
09727 }
09728 }
09729 } else {
09730 char temp[256];
09731 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
09732 if (res < 0)
09733 return res;
09734 if (ast_strlen_zero(temp))
09735 return 0;
09736 args.argv0 = ast_strdupa(temp);
09737 }
09738
09739 res = leave_voicemail(chan, args.argv0, &leave_options);
09740
09741 if (res == ERROR_LOCK_PATH) {
09742 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
09743 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
09744 res = 0;
09745 }
09746
09747 return res;
09748 }
09749
09750 static struct ast_vm_user *find_or_create(const char *context, const char *box)
09751 {
09752 struct ast_vm_user *vmu;
09753
09754 AST_LIST_TRAVERSE(&users, vmu, list) {
09755 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
09756 if (strcasecmp(vmu->context, context)) {
09757 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
09758 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
09759 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
09760 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
09761 }
09762 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
09763 return NULL;
09764 }
09765 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
09766 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
09767 return NULL;
09768 }
09769 }
09770
09771 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
09772 return NULL;
09773
09774 ast_copy_string(vmu->context, context, sizeof(vmu->context));
09775 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
09776
09777 AST_LIST_INSERT_TAIL(&users, vmu, list);
09778
09779 return vmu;
09780 }
09781
09782 static int append_mailbox(const char *context, const char *box, const char *data)
09783 {
09784
09785 char *tmp;
09786 char *stringp;
09787 char *s;
09788 struct ast_vm_user *vmu;
09789 char *mailbox_full;
09790 int new = 0, old = 0, urgent = 0;
09791
09792 tmp = ast_strdupa(data);
09793
09794 if (!(vmu = find_or_create(context, box)))
09795 return -1;
09796
09797 populate_defaults(vmu);
09798
09799 stringp = tmp;
09800 if ((s = strsep(&stringp, ",")))
09801 ast_copy_string(vmu->password, s, sizeof(vmu->password));
09802 if (stringp && (s = strsep(&stringp, ",")))
09803 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
09804 if (stringp && (s = strsep(&stringp, ",")))
09805 ast_copy_string(vmu->email, s, sizeof(vmu->email));
09806 if (stringp && (s = strsep(&stringp, ",")))
09807 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
09808 if (stringp && (s = strsep(&stringp, ",")))
09809 apply_options(vmu, s);
09810
09811 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
09812 strcpy(mailbox_full, box);
09813 strcat(mailbox_full, "@");
09814 strcat(mailbox_full, context);
09815
09816 inboxcount2(mailbox_full, &urgent, &new, &old);
09817 queue_mwi_event(mailbox_full, urgent, new, old);
09818
09819 return 0;
09820 }
09821
09822 static int vm_box_exists(struct ast_channel *chan, void *data)
09823 {
09824 struct ast_vm_user svm;
09825 char *context, *box;
09826 AST_DECLARE_APP_ARGS(args,
09827 AST_APP_ARG(mbox);
09828 AST_APP_ARG(options);
09829 );
09830 static int dep_warning = 0;
09831
09832 if (ast_strlen_zero(data)) {
09833 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
09834 return -1;
09835 }
09836
09837 if (!dep_warning) {
09838 dep_warning = 1;
09839 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *)data);
09840 }
09841
09842 box = ast_strdupa(data);
09843
09844 AST_STANDARD_APP_ARGS(args, box);
09845
09846 if (args.options) {
09847 }
09848
09849 if ((context = strchr(args.mbox, '@'))) {
09850 *context = '\0';
09851 context++;
09852 }
09853
09854 if (find_user(&svm, context, args.mbox)) {
09855 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
09856 } else
09857 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
09858
09859 return 0;
09860 }
09861
09862 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
09863 {
09864 struct ast_vm_user svm;
09865 AST_DECLARE_APP_ARGS(arg,
09866 AST_APP_ARG(mbox);
09867 AST_APP_ARG(context);
09868 );
09869
09870 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
09871
09872 if (ast_strlen_zero(arg.mbox)) {
09873 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
09874 return -1;
09875 }
09876
09877 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
09878 return 0;
09879 }
09880
09881 static struct ast_custom_function mailbox_exists_acf = {
09882 .name = "MAILBOX_EXISTS",
09883 .synopsis = "Tell if a mailbox is configured",
09884 .desc =
09885 "Returns a boolean of whether the corresponding mailbox exists. If context\n"
09886 "is not specified, defaults to the \"default\" context.\n",
09887 .syntax = "MAILBOX_EXISTS(<vmbox>[@<context>])",
09888 .read = acf_mailbox_exists,
09889 };
09890
09891 static int vmauthenticate(struct ast_channel *chan, void *data)
09892 {
09893 char *s = data, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION] = "";
09894 struct ast_vm_user vmus;
09895 char *options = NULL;
09896 int silent = 0, skipuser = 0;
09897 int res = -1;
09898
09899 if (s) {
09900 s = ast_strdupa(s);
09901 user = strsep(&s, ",");
09902 options = strsep(&s, ",");
09903 if (user) {
09904 s = user;
09905 user = strsep(&s, "@");
09906 context = strsep(&s, "");
09907 if (!ast_strlen_zero(user))
09908 skipuser++;
09909 ast_copy_string(mailbox, user, sizeof(mailbox));
09910 }
09911 }
09912
09913 if (options) {
09914 silent = (strchr(options, 's')) != NULL;
09915 }
09916
09917 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
09918 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
09919 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
09920 ast_play_and_wait(chan, "auth-thankyou");
09921 res = 0;
09922 }
09923
09924 return res;
09925 }
09926
09927 static char *show_users_realtime(int fd, const char *context)
09928 {
09929 struct ast_config *cfg;
09930 const char *cat = NULL;
09931
09932 if (!(cfg = ast_load_realtime_multientry("voicemail",
09933 "context", context, SENTINEL))) {
09934 return CLI_FAILURE;
09935 }
09936
09937 ast_cli(fd,
09938 "\n"
09939 "=============================================================\n"
09940 "=== Configured Voicemail Users ==============================\n"
09941 "=============================================================\n"
09942 "===\n");
09943
09944 while ((cat = ast_category_browse(cfg, cat))) {
09945 struct ast_variable *var = NULL;
09946 ast_cli(fd,
09947 "=== Mailbox ...\n"
09948 "===\n");
09949 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
09950 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
09951 ast_cli(fd,
09952 "===\n"
09953 "=== ---------------------------------------------------------\n"
09954 "===\n");
09955 }
09956
09957 ast_cli(fd,
09958 "=============================================================\n"
09959 "\n");
09960
09961 ast_config_destroy(cfg);
09962
09963 return CLI_SUCCESS;
09964 }
09965
09966 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
09967 {
09968 int which = 0;
09969 int wordlen;
09970 struct ast_vm_user *vmu;
09971 const char *context = "";
09972
09973
09974 if (pos > 4)
09975 return NULL;
09976 if (pos == 3)
09977 return (state == 0) ? ast_strdup("for") : NULL;
09978 wordlen = strlen(word);
09979 AST_LIST_TRAVERSE(&users, vmu, list) {
09980 if (!strncasecmp(word, vmu->context, wordlen)) {
09981 if (context && strcmp(context, vmu->context) && ++which > state)
09982 return ast_strdup(vmu->context);
09983
09984 context = vmu->context;
09985 }
09986 }
09987 return NULL;
09988 }
09989
09990
09991 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09992 {
09993 struct ast_vm_user *vmu;
09994 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
09995 const char *context = NULL;
09996 int users_counter = 0;
09997
09998 switch (cmd) {
09999 case CLI_INIT:
10000 e->command = "voicemail show users";
10001 e->usage =
10002 "Usage: voicemail show users [for <context>]\n"
10003 " Lists all mailboxes currently set up\n";
10004 return NULL;
10005 case CLI_GENERATE:
10006 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
10007 }
10008
10009 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
10010 return CLI_SHOWUSAGE;
10011 if (a->argc == 5) {
10012 if (strcmp(a->argv[3],"for"))
10013 return CLI_SHOWUSAGE;
10014 context = a->argv[4];
10015 }
10016
10017 if (ast_check_realtime("voicemail")) {
10018 if (!context) {
10019 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
10020 return CLI_SHOWUSAGE;
10021 }
10022 return show_users_realtime(a->fd, context);
10023 }
10024
10025 AST_LIST_LOCK(&users);
10026 if (AST_LIST_EMPTY(&users)) {
10027 ast_cli(a->fd, "There are no voicemail users currently defined\n");
10028 AST_LIST_UNLOCK(&users);
10029 return CLI_FAILURE;
10030 }
10031 if (a->argc == 3)
10032 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10033 else {
10034 int count = 0;
10035 AST_LIST_TRAVERSE(&users, vmu, list) {
10036 if (!strcmp(context, vmu->context))
10037 count++;
10038 }
10039 if (count) {
10040 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10041 } else {
10042 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
10043 AST_LIST_UNLOCK(&users);
10044 return CLI_FAILURE;
10045 }
10046 }
10047 AST_LIST_TRAVERSE(&users, vmu, list) {
10048 int newmsgs = 0, oldmsgs = 0;
10049 char count[12], tmp[256] = "";
10050
10051 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
10052 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
10053 inboxcount(tmp, &newmsgs, &oldmsgs);
10054 snprintf(count, sizeof(count), "%d", newmsgs);
10055 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
10056 users_counter++;
10057 }
10058 }
10059 AST_LIST_UNLOCK(&users);
10060 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
10061 return CLI_SUCCESS;
10062 }
10063
10064
10065 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10066 {
10067 struct vm_zone *zone;
10068 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
10069 char *res = CLI_SUCCESS;
10070
10071 switch (cmd) {
10072 case CLI_INIT:
10073 e->command = "voicemail show zones";
10074 e->usage =
10075 "Usage: voicemail show zones\n"
10076 " Lists zone message formats\n";
10077 return NULL;
10078 case CLI_GENERATE:
10079 return NULL;
10080 }
10081
10082 if (a->argc != 3)
10083 return CLI_SHOWUSAGE;
10084
10085 AST_LIST_LOCK(&zones);
10086 if (!AST_LIST_EMPTY(&zones)) {
10087 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
10088 AST_LIST_TRAVERSE(&zones, zone, list) {
10089 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
10090 }
10091 } else {
10092 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
10093 res = CLI_FAILURE;
10094 }
10095 AST_LIST_UNLOCK(&zones);
10096
10097 return res;
10098 }
10099
10100
10101 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10102 {
10103 switch (cmd) {
10104 case CLI_INIT:
10105 e->command = "voicemail reload";
10106 e->usage =
10107 "Usage: voicemail reload\n"
10108 " Reload voicemail configuration\n";
10109 return NULL;
10110 case CLI_GENERATE:
10111 return NULL;
10112 }
10113
10114 if (a->argc != 2)
10115 return CLI_SHOWUSAGE;
10116
10117 ast_cli(a->fd, "Reloading voicemail configuration...\n");
10118 load_config(1);
10119
10120 return CLI_SUCCESS;
10121 }
10122
10123 static struct ast_cli_entry cli_voicemail[] = {
10124 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
10125 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
10126 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
10127 };
10128
10129 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
10130 {
10131 int new = 0, old = 0, urgent = 0;
10132
10133 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
10134
10135 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
10136 mwi_sub->old_urgent = urgent;
10137 mwi_sub->old_new = new;
10138 mwi_sub->old_old = old;
10139 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
10140 }
10141 }
10142
10143 static void poll_subscribed_mailboxes(void)
10144 {
10145 struct mwi_sub *mwi_sub;
10146
10147 AST_RWLIST_RDLOCK(&mwi_subs);
10148 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
10149 if (!ast_strlen_zero(mwi_sub->mailbox)) {
10150 poll_subscribed_mailbox(mwi_sub);
10151 }
10152 }
10153 AST_RWLIST_UNLOCK(&mwi_subs);
10154 }
10155
10156 static void *mb_poll_thread(void *data)
10157 {
10158 while (poll_thread_run) {
10159 struct timespec ts = { 0, };
10160 struct timeval wait;
10161
10162 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
10163 ts.tv_sec = wait.tv_sec;
10164 ts.tv_nsec = wait.tv_usec * 1000;
10165
10166 ast_mutex_lock(&poll_lock);
10167 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
10168 ast_mutex_unlock(&poll_lock);
10169
10170 if (!poll_thread_run)
10171 break;
10172
10173 poll_subscribed_mailboxes();
10174 }
10175
10176 return NULL;
10177 }
10178
10179 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
10180 {
10181 ast_free(mwi_sub);
10182 }
10183
10184 static int handle_unsubscribe(void *datap)
10185 {
10186 struct mwi_sub *mwi_sub;
10187 uint32_t *uniqueid = datap;
10188
10189 AST_RWLIST_WRLOCK(&mwi_subs);
10190 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
10191 if (mwi_sub->uniqueid == *uniqueid) {
10192 AST_LIST_REMOVE_CURRENT(entry);
10193 break;
10194 }
10195 }
10196 AST_RWLIST_TRAVERSE_SAFE_END
10197 AST_RWLIST_UNLOCK(&mwi_subs);
10198
10199 if (mwi_sub)
10200 mwi_sub_destroy(mwi_sub);
10201
10202 ast_free(uniqueid);
10203 return 0;
10204 }
10205
10206 static int handle_subscribe(void *datap)
10207 {
10208 unsigned int len;
10209 struct mwi_sub *mwi_sub;
10210 struct mwi_sub_task *p = datap;
10211
10212 len = sizeof(*mwi_sub);
10213 if (!ast_strlen_zero(p->mailbox))
10214 len += strlen(p->mailbox);
10215
10216 if (!ast_strlen_zero(p->context))
10217 len += strlen(p->context) + 1;
10218
10219 if (!(mwi_sub = ast_calloc(1, len)))
10220 return -1;
10221
10222 mwi_sub->uniqueid = p->uniqueid;
10223 if (!ast_strlen_zero(p->mailbox))
10224 strcpy(mwi_sub->mailbox, p->mailbox);
10225
10226 if (!ast_strlen_zero(p->context)) {
10227 strcat(mwi_sub->mailbox, "@");
10228 strcat(mwi_sub->mailbox, p->context);
10229 }
10230
10231 AST_RWLIST_WRLOCK(&mwi_subs);
10232 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
10233 AST_RWLIST_UNLOCK(&mwi_subs);
10234 ast_free((void *) p->mailbox);
10235 ast_free((void *) p->context);
10236 ast_free(p);
10237 poll_subscribed_mailbox(mwi_sub);
10238 return 0;
10239 }
10240
10241 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
10242 {
10243 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
10244 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
10245 return;
10246
10247 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
10248 return;
10249
10250 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
10251 *uniqueid = u;
10252 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
10253 ast_free(uniqueid);
10254 }
10255 }
10256
10257 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
10258 {
10259 struct mwi_sub_task *mwist;
10260
10261 if (ast_event_get_type(event) != AST_EVENT_SUB)
10262 return;
10263
10264 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
10265 return;
10266
10267 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
10268 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
10269 return;
10270 }
10271 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
10272 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
10273 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
10274
10275 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
10276 ast_free(mwist);
10277 }
10278 }
10279
10280 static void start_poll_thread(void)
10281 {
10282 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, NULL,
10283 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
10284 AST_EVENT_IE_END);
10285
10286 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, NULL,
10287 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
10288 AST_EVENT_IE_END);
10289
10290 if (mwi_sub_sub)
10291 ast_event_report_subs(mwi_sub_sub);
10292
10293 poll_thread_run = 1;
10294
10295 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
10296 }
10297
10298 static void stop_poll_thread(void)
10299 {
10300 poll_thread_run = 0;
10301
10302 if (mwi_sub_sub) {
10303 ast_event_unsubscribe(mwi_sub_sub);
10304 mwi_sub_sub = NULL;
10305 }
10306
10307 if (mwi_unsub_sub) {
10308 ast_event_unsubscribe(mwi_unsub_sub);
10309 mwi_unsub_sub = NULL;
10310 }
10311
10312 ast_mutex_lock(&poll_lock);
10313 ast_cond_signal(&poll_cond);
10314 ast_mutex_unlock(&poll_lock);
10315
10316 pthread_join(poll_thread, NULL);
10317
10318 poll_thread = AST_PTHREADT_NULL;
10319 }
10320
10321
10322 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
10323 {
10324 struct ast_vm_user *vmu = NULL;
10325 const char *id = astman_get_header(m, "ActionID");
10326 char actionid[128] = "";
10327
10328 if (!ast_strlen_zero(id))
10329 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
10330
10331 AST_LIST_LOCK(&users);
10332
10333 if (AST_LIST_EMPTY(&users)) {
10334 astman_send_ack(s, m, "There are no voicemail users currently defined.");
10335 AST_LIST_UNLOCK(&users);
10336 return RESULT_SUCCESS;
10337 }
10338
10339 astman_send_ack(s, m, "Voicemail user list will follow");
10340
10341 AST_LIST_TRAVERSE(&users, vmu, list) {
10342 char dirname[256];
10343
10344 #ifdef IMAP_STORAGE
10345 int new, old;
10346 inboxcount(vmu->mailbox, &new, &old);
10347 #endif
10348
10349 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
10350 astman_append(s,
10351 "%s"
10352 "Event: VoicemailUserEntry\r\n"
10353 "VMContext: %s\r\n"
10354 "VoiceMailbox: %s\r\n"
10355 "Fullname: %s\r\n"
10356 "Email: %s\r\n"
10357 "Pager: %s\r\n"
10358 "ServerEmail: %s\r\n"
10359 "MailCommand: %s\r\n"
10360 "Language: %s\r\n"
10361 "TimeZone: %s\r\n"
10362 "Callback: %s\r\n"
10363 "Dialout: %s\r\n"
10364 "UniqueID: %s\r\n"
10365 "ExitContext: %s\r\n"
10366 "SayDurationMinimum: %d\r\n"
10367 "SayEnvelope: %s\r\n"
10368 "SayCID: %s\r\n"
10369 "AttachMessage: %s\r\n"
10370 "AttachmentFormat: %s\r\n"
10371 "DeleteMessage: %s\r\n"
10372 "VolumeGain: %.2f\r\n"
10373 "CanReview: %s\r\n"
10374 "CallOperator: %s\r\n"
10375 "MaxMessageCount: %d\r\n"
10376 "MaxMessageLength: %d\r\n"
10377 "NewMessageCount: %d\r\n"
10378 #ifdef IMAP_STORAGE
10379 "OldMessageCount: %d\r\n"
10380 "IMAPUser: %s\r\n"
10381 #endif
10382 "\r\n",
10383 actionid,
10384 vmu->context,
10385 vmu->mailbox,
10386 vmu->fullname,
10387 vmu->email,
10388 vmu->pager,
10389 vmu->serveremail,
10390 vmu->mailcmd,
10391 vmu->language,
10392 vmu->zonetag,
10393 vmu->callback,
10394 vmu->dialout,
10395 vmu->uniqueid,
10396 vmu->exit,
10397 vmu->saydurationm,
10398 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
10399 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
10400 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
10401 vmu->attachfmt,
10402 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
10403 vmu->volgain,
10404 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
10405 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
10406 vmu->maxmsg,
10407 vmu->maxsecs,
10408 #ifdef IMAP_STORAGE
10409 new, old, vmu->imapuser
10410 #else
10411 count_messages(vmu, dirname)
10412 #endif
10413 );
10414 }
10415 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
10416
10417 AST_LIST_UNLOCK(&users);
10418
10419 return RESULT_SUCCESS;
10420 }
10421
10422
10423 static void free_vm_users(void)
10424 {
10425 struct ast_vm_user *current;
10426 AST_LIST_LOCK(&users);
10427 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
10428 ast_set_flag(current, VM_ALLOCED);
10429 free_user(current);
10430 }
10431 AST_LIST_UNLOCK(&users);
10432 }
10433
10434
10435 static void free_vm_zones(void)
10436 {
10437 struct vm_zone *zcur;
10438 AST_LIST_LOCK(&zones);
10439 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
10440 free_zone(zcur);
10441 AST_LIST_UNLOCK(&zones);
10442 }
10443
10444 static char *substitute_escapes(const char *value)
10445 {
10446 char *current, *result;
10447
10448
10449 struct ast_str *str = ast_str_create(strlen(value) + 16);
10450
10451
10452 for (current = (char *) value; *current; current++) {
10453 if (*current == '\\') {
10454 current++;
10455 if (!*current) {
10456 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
10457 break;
10458 }
10459 switch (*current) {
10460 case 'r':
10461 ast_str_append(&str, 0, "\r");
10462 break;
10463 case 'n':
10464 #ifdef IMAP_STORAGE
10465 if (!str->used || str->str[str->used - 1] != '\r') {
10466 ast_str_append(&str, 0, "\r");
10467 }
10468 #endif
10469 ast_str_append(&str, 0, "\n");
10470 break;
10471 case 't':
10472 ast_str_append(&str, 0, "\t");
10473 break;
10474 default:
10475 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
10476 break;
10477 }
10478 } else {
10479 ast_str_append(&str, 0, "%c", *current);
10480 }
10481 }
10482
10483 result = ast_strdup(str->str);
10484 ast_free(str);
10485
10486 return result;
10487 }
10488
10489 static int load_config(int reload)
10490 {
10491 struct ast_vm_user *current;
10492 struct ast_config *cfg, *ucfg;
10493 char *cat;
10494 struct ast_variable *var;
10495 const char *val;
10496 char *q, *stringp, *tmp;
10497 int x;
10498 int tmpadsi[4];
10499 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10500
10501 ast_unload_realtime("voicemail");
10502 ast_unload_realtime("voicemail_data");
10503
10504 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
10505 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
10506 return 0;
10507 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
10508 cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
10509 } else {
10510 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
10511 ucfg = ast_config_load("users.conf", config_flags);
10512 }
10513 #ifdef IMAP_STORAGE
10514 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
10515 #endif
10516
10517 strcpy(listen_control_forward_key,DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
10518 strcpy(listen_control_reverse_key,DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
10519 strcpy(listen_control_pause_key,DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
10520 strcpy(listen_control_restart_key,DEFAULT_LISTEN_CONTROL_RESTART_KEY);
10521 strcpy(listen_control_stop_key,DEFAULT_LISTEN_CONTROL_STOP_KEY);
10522
10523
10524 free_vm_users();
10525
10526
10527 free_vm_zones();
10528
10529 AST_LIST_LOCK(&users);
10530
10531 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
10532 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
10533
10534 if (cfg) {
10535
10536
10537 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
10538 val = "default";
10539 ast_copy_string(userscontext, val, sizeof(userscontext));
10540
10541 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
10542 val = "yes";
10543 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
10544
10545 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
10546 val = "no";
10547 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
10548
10549 volgain = 0.0;
10550 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
10551 sscanf(val, "%30lf", &volgain);
10552
10553 #ifdef ODBC_STORAGE
10554 strcpy(odbc_database, "asterisk");
10555 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
10556 ast_copy_string(odbc_database, val, sizeof(odbc_database));
10557 }
10558 strcpy(odbc_table, "voicemessages");
10559 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
10560 ast_copy_string(odbc_table, val, sizeof(odbc_table));
10561 }
10562 #endif
10563
10564 strcpy(mailcmd, SENDMAIL);
10565 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
10566 ast_copy_string(mailcmd, val, sizeof(mailcmd));
10567
10568 maxsilence = 0;
10569 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
10570 maxsilence = atoi(val);
10571 if (maxsilence > 0)
10572 maxsilence *= 1000;
10573 }
10574
10575 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
10576 maxmsg = MAXMSG;
10577 } else {
10578 maxmsg = atoi(val);
10579 if (maxmsg <= 0) {
10580 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
10581 maxmsg = MAXMSG;
10582 } else if (maxmsg > MAXMSGLIMIT) {
10583 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
10584 maxmsg = MAXMSGLIMIT;
10585 }
10586 }
10587
10588 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
10589 maxdeletedmsg = 0;
10590 } else {
10591 if (sscanf(val, "%30d", &x) == 1)
10592 maxdeletedmsg = x;
10593 else if (ast_true(val))
10594 maxdeletedmsg = MAXMSG;
10595 else
10596 maxdeletedmsg = 0;
10597
10598 if (maxdeletedmsg < 0) {
10599 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
10600 maxdeletedmsg = MAXMSG;
10601 } else if (maxdeletedmsg > MAXMSGLIMIT) {
10602 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
10603 maxdeletedmsg = MAXMSGLIMIT;
10604 }
10605 }
10606
10607
10608 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
10609 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
10610 }
10611
10612
10613 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
10614 ast_copy_string(ext_pass_cmd,val,sizeof(ext_pass_cmd));
10615 pwdchange = PWDCHANGE_EXTERNAL;
10616 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
10617 ast_copy_string(ext_pass_cmd,val,sizeof(ext_pass_cmd));
10618 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
10619 }
10620
10621
10622 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
10623 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
10624 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
10625 }
10626
10627 #ifdef IMAP_STORAGE
10628
10629 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
10630 ast_copy_string(imapserver, val, sizeof(imapserver));
10631 } else {
10632 ast_copy_string(imapserver,"localhost", sizeof(imapserver));
10633 }
10634
10635 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
10636 ast_copy_string(imapport, val, sizeof(imapport));
10637 } else {
10638 ast_copy_string(imapport,"143", sizeof(imapport));
10639 }
10640
10641 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
10642 ast_copy_string(imapflags, val, sizeof(imapflags));
10643 }
10644
10645 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
10646 ast_copy_string(authuser, val, sizeof(authuser));
10647 }
10648
10649 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
10650 ast_copy_string(authpassword, val, sizeof(authpassword));
10651 }
10652
10653 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
10654 if (ast_false(val))
10655 expungeonhangup = 0;
10656 else
10657 expungeonhangup = 1;
10658 } else {
10659 expungeonhangup = 1;
10660 }
10661
10662 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
10663 ast_copy_string(imapfolder, val, sizeof(imapfolder));
10664 } else {
10665 ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
10666 }
10667 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
10668 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
10669 }
10670 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
10671 imapgreetings = ast_true(val);
10672 } else {
10673 imapgreetings = 0;
10674 }
10675 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
10676 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
10677 } else {
10678 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
10679 }
10680
10681
10682
10683
10684
10685 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
10686 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
10687 } else {
10688 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
10689 }
10690
10691 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
10692 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
10693 } else {
10694 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
10695 }
10696
10697 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
10698 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
10699 } else {
10700 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
10701 }
10702
10703 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
10704 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
10705 } else {
10706 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
10707 }
10708
10709
10710 imapversion++;
10711 #endif
10712
10713 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
10714 ast_copy_string(externnotify, val, sizeof(externnotify));
10715 ast_debug(1, "found externnotify: %s\n", externnotify);
10716 } else {
10717 externnotify[0] = '\0';
10718 }
10719
10720
10721 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
10722 ast_debug(1, "Enabled SMDI voicemail notification\n");
10723 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
10724 smdi_iface = ast_smdi_interface_find ? ast_smdi_interface_find(val) : NULL;
10725 } else {
10726 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
10727 smdi_iface = ast_smdi_interface_find ? ast_smdi_interface_find("/dev/ttyS0") : NULL;
10728 }
10729 if (!smdi_iface) {
10730 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
10731 }
10732 }
10733
10734
10735 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
10736 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
10737 silencethreshold = atoi(val);
10738
10739 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
10740 val = ASTERISK_USERNAME;
10741 ast_copy_string(serveremail, val, sizeof(serveremail));
10742
10743 vmmaxsecs = 0;
10744 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
10745 if (sscanf(val, "%30d", &x) == 1) {
10746 vmmaxsecs = x;
10747 } else {
10748 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
10749 }
10750 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
10751 static int maxmessage_deprecate = 0;
10752 if (maxmessage_deprecate == 0) {
10753 maxmessage_deprecate = 1;
10754 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
10755 }
10756 if (sscanf(val, "%30d", &x) == 1) {
10757 vmmaxsecs = x;
10758 } else {
10759 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
10760 }
10761 }
10762
10763 vmminsecs = 0;
10764 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
10765 if (sscanf(val, "%30d", &x) == 1) {
10766 vmminsecs = x;
10767 if (maxsilence / 1000 >= vmminsecs) {
10768 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
10769 }
10770 } else {
10771 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
10772 }
10773 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
10774 static int maxmessage_deprecate = 0;
10775 if (maxmessage_deprecate == 0) {
10776 maxmessage_deprecate = 1;
10777 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
10778 }
10779 if (sscanf(val, "%30d", &x) == 1) {
10780 vmminsecs = x;
10781 if (maxsilence / 1000 >= vmminsecs) {
10782 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
10783 }
10784 } else {
10785 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
10786 }
10787 }
10788
10789 val = ast_variable_retrieve(cfg, "general", "format");
10790 if (!val) {
10791 val = "wav";
10792 } else {
10793 tmp = ast_strdupa(val);
10794 val = ast_format_str_reduce(tmp);
10795 if (!val) {
10796 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
10797 val = "wav";
10798 }
10799 }
10800 ast_copy_string(vmfmts, val, sizeof(vmfmts));
10801
10802 skipms = 3000;
10803 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
10804 if (sscanf(val, "%30d", &x) == 1) {
10805 maxgreet = x;
10806 } else {
10807 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
10808 }
10809 }
10810
10811 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
10812 if (sscanf(val, "%30d", &x) == 1) {
10813 skipms = x;
10814 } else {
10815 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
10816 }
10817 }
10818
10819 maxlogins = 3;
10820 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
10821 if (sscanf(val, "%30d", &x) == 1) {
10822 maxlogins = x;
10823 } else {
10824 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
10825 }
10826 }
10827
10828 minpassword = MINPASSWORD;
10829 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
10830 if (sscanf(val, "%30d", &x) == 1) {
10831 minpassword = x;
10832 } else {
10833 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
10834 }
10835 }
10836
10837
10838 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
10839 val = "no";
10840 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
10841
10842
10843 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
10844 val = "no";
10845 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
10846
10847 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
10848 ast_debug(1, "VM_CID Internal context string: %s\n", val);
10849 stringp = ast_strdupa(val);
10850 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
10851 if (!ast_strlen_zero(stringp)) {
10852 q = strsep(&stringp, ",");
10853 while ((*q == ' ')||(*q == '\t'))
10854 q++;
10855 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
10856 ast_debug(1,"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
10857 } else {
10858 cidinternalcontexts[x][0] = '\0';
10859 }
10860 }
10861 }
10862 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
10863 ast_debug(1,"VM Review Option disabled globally\n");
10864 val = "no";
10865 }
10866 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
10867
10868
10869 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
10870 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
10871 val = "no";
10872 } else {
10873 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
10874 }
10875 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
10876 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
10877 ast_debug(1, "VM next message wrap disabled globally\n");
10878 val = "no";
10879 }
10880 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
10881
10882 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
10883 ast_debug(1,"VM Operator break disabled globally\n");
10884 val = "no";
10885 }
10886 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
10887
10888 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
10889 ast_debug(1,"VM CID Info before msg disabled globally\n");
10890 val = "no";
10891 }
10892 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
10893
10894 if (!(val = ast_variable_retrieve(cfg,"general", "sendvoicemail"))){
10895 ast_debug(1,"Send Voicemail msg disabled globally\n");
10896 val = "no";
10897 }
10898 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
10899
10900 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
10901 ast_debug(1,"ENVELOPE before msg enabled globally\n");
10902 val = "yes";
10903 }
10904 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
10905
10906 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
10907 ast_debug(1,"Move Heard enabled globally\n");
10908 val = "yes";
10909 }
10910 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
10911
10912 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
10913 ast_debug(1,"Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
10914 val = "no";
10915 }
10916 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
10917
10918 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
10919 ast_debug(1,"Duration info before msg enabled globally\n");
10920 val = "yes";
10921 }
10922 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
10923
10924 saydurationminfo = 2;
10925 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
10926 if (sscanf(val, "%30d", &x) == 1) {
10927 saydurationminfo = x;
10928 } else {
10929 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
10930 }
10931 }
10932
10933 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
10934 ast_debug(1,"We are not going to skip to the next msg after save/delete\n");
10935 val = "no";
10936 }
10937 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
10938
10939 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
10940 ast_copy_string(dialcontext, val, sizeof(dialcontext));
10941 ast_debug(1, "found dialout context: %s\n", dialcontext);
10942 } else {
10943 dialcontext[0] = '\0';
10944 }
10945
10946 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
10947 ast_copy_string(callcontext, val, sizeof(callcontext));
10948 ast_debug(1, "found callback context: %s\n", callcontext);
10949 } else {
10950 callcontext[0] = '\0';
10951 }
10952
10953 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
10954 ast_copy_string(exitcontext, val, sizeof(exitcontext));
10955 ast_debug(1, "found operator context: %s\n", exitcontext);
10956 } else {
10957 exitcontext[0] = '\0';
10958 }
10959
10960
10961 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
10962 ast_copy_string(vm_password, val, sizeof(vm_password));
10963 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
10964 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
10965 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
10966 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
10967 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
10968 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
10969 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
10970 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
10971 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
10972 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
10973 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
10974 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
10975 }
10976
10977 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
10978 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
10979 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
10980 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
10981 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
10982 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
10983 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
10984 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
10985 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
10986 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
10987
10988 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
10989 val = "no";
10990 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
10991
10992 poll_freq = DEFAULT_POLL_FREQ;
10993 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
10994 if (sscanf(val, "%30u", &poll_freq) != 1) {
10995 poll_freq = DEFAULT_POLL_FREQ;
10996 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
10997 }
10998 }
10999
11000 poll_mailboxes = 0;
11001 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
11002 poll_mailboxes = ast_true(val);
11003
11004 if (ucfg) {
11005 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
11006 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
11007 continue;
11008 if ((current = find_or_create(userscontext, cat))) {
11009 populate_defaults(current);
11010 apply_options_full(current, ast_variable_browse(ucfg, cat));
11011 ast_copy_string(current->context, userscontext, sizeof(current->context));
11012 }
11013 }
11014 ast_config_destroy(ucfg);
11015 }
11016 cat = ast_category_browse(cfg, NULL);
11017 while (cat) {
11018 if (strcasecmp(cat, "general")) {
11019 var = ast_variable_browse(cfg, cat);
11020 if (strcasecmp(cat, "zonemessages")) {
11021
11022 while (var) {
11023 append_mailbox(cat, var->name, var->value);
11024 var = var->next;
11025 }
11026 } else {
11027
11028 while (var) {
11029 struct vm_zone *z;
11030 if ((z = ast_malloc(sizeof(*z)))) {
11031 char *msg_format, *tzone;
11032 msg_format = ast_strdupa(var->value);
11033 tzone = strsep(&msg_format, "|");
11034 if (msg_format) {
11035 ast_copy_string(z->name, var->name, sizeof(z->name));
11036 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
11037 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
11038 AST_LIST_LOCK(&zones);
11039 AST_LIST_INSERT_HEAD(&zones, z, list);
11040 AST_LIST_UNLOCK(&zones);
11041 } else {
11042 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
11043 ast_free(z);
11044 }
11045 } else {
11046 AST_LIST_UNLOCK(&users);
11047 ast_config_destroy(cfg);
11048 return -1;
11049 }
11050 var = var->next;
11051 }
11052 }
11053 }
11054 cat = ast_category_browse(cfg, cat);
11055 }
11056 memset(fromstring, 0, sizeof(fromstring));
11057 memset(pagerfromstring, 0, sizeof(pagerfromstring));
11058 strcpy(charset, "ISO-8859-1");
11059 if (emailbody) {
11060 ast_free(emailbody);
11061 emailbody = NULL;
11062 }
11063 if (emailsubject) {
11064 ast_free(emailsubject);
11065 emailsubject = NULL;
11066 }
11067 if (pagerbody) {
11068 ast_free(pagerbody);
11069 pagerbody = NULL;
11070 }
11071 if (pagersubject) {
11072 ast_free(pagersubject);
11073 pagersubject = NULL;
11074 }
11075 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
11076 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
11077 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
11078 ast_copy_string(fromstring, val, sizeof(fromstring));
11079 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
11080 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
11081 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
11082 ast_copy_string(charset, val, sizeof(charset));
11083 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
11084 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
11085 for (x = 0; x < 4; x++) {
11086 memcpy(&adsifdn[x], &tmpadsi[x], 1);
11087 }
11088 }
11089 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
11090 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
11091 for (x = 0; x < 4; x++) {
11092 memcpy(&adsisec[x], &tmpadsi[x], 1);
11093 }
11094 }
11095 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
11096 if (atoi(val)) {
11097 adsiver = atoi(val);
11098 }
11099 }
11100 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
11101 ast_copy_string(zonetag, val, sizeof(zonetag));
11102 }
11103 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
11104 emailsubject = ast_strdup(val);
11105 }
11106 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
11107 emailbody = substitute_escapes(val);
11108 }
11109 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
11110 pagersubject = ast_strdup(val);
11111 }
11112 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
11113 pagerbody = substitute_escapes(val);
11114 }
11115 AST_LIST_UNLOCK(&users);
11116 ast_config_destroy(cfg);
11117
11118 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
11119 start_poll_thread();
11120 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
11121 stop_poll_thread();;
11122
11123 return 0;
11124 } else {
11125 AST_LIST_UNLOCK(&users);
11126 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
11127 if (ucfg)
11128 ast_config_destroy(ucfg);
11129 return 0;
11130 }
11131 }
11132
11133 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
11134 {
11135 int res = -1;
11136 char dir[PATH_MAX];
11137 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
11138 ast_debug(2, "About to try retrieving name file %s\n", dir);
11139 RETRIEVE(dir, -1, mailbox, context);
11140 if (ast_fileexists(dir, NULL, NULL)) {
11141 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
11142 }
11143 DISPOSE(dir, -1);
11144 return res;
11145 }
11146
11147 static int reload(void)
11148 {
11149 return load_config(1);
11150 }
11151
11152 static int unload_module(void)
11153 {
11154 int res;
11155
11156 res = ast_unregister_application(app);
11157 res |= ast_unregister_application(app2);
11158 res |= ast_unregister_application(app3);
11159 res |= ast_unregister_application(app4);
11160 res |= ast_custom_function_unregister(&mailbox_exists_acf);
11161 res |= ast_manager_unregister("VoicemailUsersList");
11162 ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
11163 ast_uninstall_vm_functions();
11164 ao2_ref(inprocess_container, -1);
11165
11166 if (poll_thread != AST_PTHREADT_NULL)
11167 stop_poll_thread();
11168
11169 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
11170 ast_unload_realtime("voicemail");
11171 ast_unload_realtime("voicemail_data");
11172
11173 free_vm_users();
11174 free_vm_zones();
11175 return res;
11176 }
11177
11178 static int load_module(void)
11179 {
11180 int res;
11181 my_umask = umask(0);
11182 umask(my_umask);
11183
11184 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
11185 return AST_MODULE_LOAD_DECLINE;
11186 }
11187
11188
11189 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
11190
11191 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
11192 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
11193 }
11194
11195 if ((res = load_config(0)))
11196 return res;
11197
11198 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
11199 res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
11200 res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
11201 res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate);
11202 res |= ast_custom_function_register(&mailbox_exists_acf);
11203 res |= ast_manager_register("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users, "List All Voicemail User Information");
11204 if (res)
11205 return res;
11206
11207 ast_cli_register_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
11208
11209 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
11210 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
11211 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
11212
11213 return res;
11214 }
11215
11216 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
11217 {
11218 int cmd = 0;
11219 char destination[80] = "";
11220 int retries = 0;
11221
11222 if (!num) {
11223 ast_verb(3, "Destination number will be entered manually\n");
11224 while (retries < 3 && cmd != 't') {
11225 destination[1] = '\0';
11226 destination[0] = cmd = ast_play_and_wait(chan,"vm-enter-num-to-call");
11227 if (!cmd)
11228 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
11229 if (!cmd)
11230 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
11231 if (!cmd) {
11232 cmd = ast_waitfordigit(chan, 6000);
11233 if (cmd)
11234 destination[0] = cmd;
11235 }
11236 if (!cmd) {
11237 retries++;
11238 } else {
11239
11240 if (cmd < 0)
11241 return 0;
11242 if (cmd == '*') {
11243 ast_verb(3, "User hit '*' to cancel outgoing call\n");
11244 return 0;
11245 }
11246 if ((cmd = ast_readstring(chan,destination + strlen(destination),sizeof(destination)-1,6000,10000,"#")) < 0)
11247 retries++;
11248 else
11249 cmd = 't';
11250 }
11251 }
11252 if (retries >= 3) {
11253 return 0;
11254 }
11255
11256 } else {
11257 if (option_verbose > 2)
11258 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
11259 ast_copy_string(destination, num, sizeof(destination));
11260 }
11261
11262 if (!ast_strlen_zero(destination)) {
11263 if (destination[strlen(destination) -1 ] == '*')
11264 return 0;
11265 if (option_verbose > 2)
11266 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
11267 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
11268 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
11269 chan->priority = 0;
11270 return 9;
11271 }
11272 return 0;
11273 }
11274
11275
11276
11277
11278
11279
11280
11281
11282
11283
11284
11285
11286
11287
11288 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)
11289 {
11290 int res = 0;
11291 char filename[PATH_MAX];
11292 struct ast_config *msg_cfg = NULL;
11293 const char *origtime, *context;
11294 char *name, *num;
11295 int retries = 0;
11296 char *cid;
11297 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
11298
11299 vms->starting = 0;
11300
11301 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
11302
11303
11304 snprintf(filename,sizeof(filename), "%s.txt", vms->fn);
11305 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
11306 msg_cfg = ast_config_load(filename, config_flags);
11307 DISPOSE(vms->curdir, vms->curmsg);
11308 if (!msg_cfg) {
11309 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
11310 return 0;
11311 }
11312
11313 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
11314 ast_config_destroy(msg_cfg);
11315 return 0;
11316 }
11317
11318 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
11319
11320 context = ast_variable_retrieve(msg_cfg, "message", "context");
11321 if (!strncasecmp("macro",context,5))
11322 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
11323 switch (option) {
11324 case 3:
11325 if (!res)
11326 res = play_message_datetime(chan, vmu, origtime, filename);
11327 if (!res)
11328 res = play_message_callerid(chan, vms, cid, context, 0);
11329
11330 res = 't';
11331 break;
11332
11333 case 2:
11334
11335 if (ast_strlen_zero(cid))
11336 break;
11337
11338 ast_callerid_parse(cid, &name, &num);
11339 while ((res > -1) && (res != 't')) {
11340 switch (res) {
11341 case '1':
11342 if (num) {
11343
11344 res = dialout(chan, vmu, num, vmu->callback);
11345 if (res) {
11346 ast_config_destroy(msg_cfg);
11347 return 9;
11348 }
11349 } else {
11350 res = '2';
11351 }
11352 break;
11353
11354 case '2':
11355
11356 if (!ast_strlen_zero(vmu->dialout)) {
11357 res = dialout(chan, vmu, NULL, vmu->dialout);
11358 if (res) {
11359 ast_config_destroy(msg_cfg);
11360 return 9;
11361 }
11362 } else {
11363 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
11364 res = ast_play_and_wait(chan, "vm-sorry");
11365 }
11366 ast_config_destroy(msg_cfg);
11367 return res;
11368 case '*':
11369 res = 't';
11370 break;
11371 case '3':
11372 case '4':
11373 case '5':
11374 case '6':
11375 case '7':
11376 case '8':
11377 case '9':
11378 case '0':
11379
11380 res = ast_play_and_wait(chan, "vm-sorry");
11381 retries++;
11382 break;
11383 default:
11384 if (num) {
11385 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
11386 res = ast_play_and_wait(chan, "vm-num-i-have");
11387 if (!res)
11388 res = play_message_callerid(chan, vms, num, vmu->context, 1);
11389 if (!res)
11390 res = ast_play_and_wait(chan, "vm-tocallnum");
11391
11392 if (!ast_strlen_zero(vmu->dialout)) {
11393 if (!res)
11394 res = ast_play_and_wait(chan, "vm-calldiffnum");
11395 }
11396 } else {
11397 res = ast_play_and_wait(chan, "vm-nonumber");
11398 if (!ast_strlen_zero(vmu->dialout)) {
11399 if (!res)
11400 res = ast_play_and_wait(chan, "vm-toenternumber");
11401 }
11402 }
11403 if (!res)
11404 res = ast_play_and_wait(chan, "vm-star-cancel");
11405 if (!res)
11406 res = ast_waitfordigit(chan, 6000);
11407 if (!res) {
11408 retries++;
11409 if (retries > 3)
11410 res = 't';
11411 }
11412 break;
11413
11414 }
11415 if (res == 't')
11416 res = 0;
11417 else if (res == '*')
11418 res = -1;
11419 }
11420 break;
11421
11422 case 1:
11423
11424 if (ast_strlen_zero(cid))
11425 break;
11426
11427 ast_callerid_parse(cid, &name, &num);
11428 if (!num) {
11429 ast_verb(3, "No CID number available, no reply sent\n");
11430 if (!res)
11431 res = ast_play_and_wait(chan, "vm-nonumber");
11432 ast_config_destroy(msg_cfg);
11433 return res;
11434 } else {
11435 struct ast_vm_user vmu2;
11436 if (find_user(&vmu2, vmu->context, num)) {
11437 struct leave_vm_options leave_options;
11438 char mailbox[AST_MAX_EXTENSION * 2 + 2];
11439 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
11440
11441 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
11442
11443 memset(&leave_options, 0, sizeof(leave_options));
11444 leave_options.record_gain = record_gain;
11445 res = leave_voicemail(chan, mailbox, &leave_options);
11446 if (!res)
11447 res = 't';
11448 ast_config_destroy(msg_cfg);
11449 return res;
11450 } else {
11451
11452 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
11453 ast_play_and_wait(chan, "vm-nobox");
11454 res = 't';
11455 ast_config_destroy(msg_cfg);
11456 return res;
11457 }
11458 }
11459 res = 0;
11460
11461 break;
11462 }
11463
11464 #ifndef IMAP_STORAGE
11465 ast_config_destroy(msg_cfg);
11466
11467 if (!res) {
11468 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
11469 vms->heard[msg] = 1;
11470 res = wait_file(chan, vms, vms->fn);
11471 }
11472 #endif
11473 return res;
11474 }
11475
11476 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
11477 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
11478 signed char record_gain, struct vm_state *vms, char *flag)
11479 {
11480
11481 int res = 0;
11482 int cmd = 0;
11483 int max_attempts = 3;
11484 int attempts = 0;
11485 int recorded = 0;
11486 int msg_exists = 0;
11487 signed char zero_gain = 0;
11488 char tempfile[PATH_MAX];
11489 char *acceptdtmf = "#";
11490 char *canceldtmf = "";
11491
11492
11493
11494
11495 if (duration == NULL) {
11496 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
11497 return -1;
11498 }
11499
11500 if (!outsidecaller)
11501 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
11502 else
11503 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
11504
11505 cmd = '3';
11506
11507 while ((cmd >= 0) && (cmd != 't')) {
11508 switch (cmd) {
11509 case '1':
11510 if (!msg_exists) {
11511
11512 cmd = '3';
11513 break;
11514 } else {
11515
11516 ast_verb(3, "Saving message as is\n");
11517 if (!outsidecaller)
11518 ast_filerename(tempfile, recordfile, NULL);
11519 ast_stream_and_wait(chan, "vm-msgsaved", "");
11520 if (!outsidecaller) {
11521
11522 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
11523 DISPOSE(recordfile, -1);
11524 }
11525 cmd = 't';
11526 return res;
11527 }
11528 case '2':
11529
11530 ast_verb(3, "Reviewing the message\n");
11531 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
11532 break;
11533 case '3':
11534 msg_exists = 0;
11535
11536 if (recorded == 1)
11537 ast_verb(3, "Re-recording the message\n");
11538 else
11539 ast_verb(3, "Recording the message\n");
11540
11541 if (recorded && outsidecaller) {
11542 cmd = ast_play_and_wait(chan, INTRO);
11543 cmd = ast_play_and_wait(chan, "beep");
11544 }
11545 recorded = 1;
11546
11547 if (record_gain)
11548 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
11549 if (ast_test_flag(vmu, VM_OPERATOR))
11550 canceldtmf = "0";
11551 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
11552 if (record_gain)
11553 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
11554 if (cmd == -1) {
11555
11556 if (!outsidecaller) {
11557
11558 ast_filedelete(tempfile, NULL);
11559 }
11560 return cmd;
11561 }
11562 if (cmd == '0') {
11563 break;
11564 } else if (cmd == '*') {
11565 break;
11566 #if 0
11567 } else if (vmu->review && (*duration < 5)) {
11568
11569 ast_verb(3, "Message too short\n");
11570 cmd = ast_play_and_wait(chan, "vm-tooshort");
11571 cmd = ast_filedelete(tempfile, NULL);
11572 break;
11573 } else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
11574
11575 ast_verb(3, "Nothing recorded\n");
11576 cmd = ast_filedelete(tempfile, NULL);
11577 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
11578 if (!cmd)
11579 cmd = ast_play_and_wait(chan, "vm-speakup");
11580 break;
11581 #endif
11582 } else {
11583
11584 msg_exists = 1;
11585 cmd = 0;
11586 }
11587 break;
11588 case '4':
11589 if (outsidecaller) {
11590
11591 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
11592 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
11593 ast_debug(1000, "This message is too urgent!\n");
11594 res = ast_play_and_wait(chan, "vm-marked-urgent");
11595 strcpy(flag, "Urgent");
11596 } else if (flag) {
11597 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
11598 res = ast_play_and_wait(chan, "vm-urgent-removed");
11599 strcpy(flag, "");
11600 } else {
11601 ast_play_and_wait(chan, "vm-sorry");
11602 }
11603 cmd = 0;
11604 } else {
11605 cmd = ast_play_and_wait(chan, "vm-sorry");
11606 }
11607 break;
11608 case '5':
11609 case '6':
11610 case '7':
11611 case '8':
11612 case '9':
11613 case '*':
11614 case '#':
11615 cmd = ast_play_and_wait(chan, "vm-sorry");
11616 break;
11617 #if 0
11618
11619
11620 case '*':
11621
11622 cmd = ast_play_and_wait(chan, "vm-deleted");
11623 cmd = ast_filedelete(tempfile, NULL);
11624 if (outsidecaller) {
11625 res = vm_exec(chan, NULL);
11626 return res;
11627 }
11628 else
11629 return 1;
11630 #endif
11631 case '0':
11632 if (!ast_test_flag(vmu, VM_OPERATOR)) {
11633 cmd = ast_play_and_wait(chan, "vm-sorry");
11634 break;
11635 }
11636 if (msg_exists || recorded) {
11637 cmd = ast_play_and_wait(chan, "vm-saveoper");
11638 if (!cmd)
11639 cmd = ast_waitfordigit(chan, 3000);
11640 if (cmd == '1') {
11641 ast_play_and_wait(chan, "vm-msgsaved");
11642 cmd = '0';
11643 } else if (cmd == '4') {
11644 if (flag) {
11645 ast_play_and_wait(chan, "vm-marked-urgent");
11646 strcpy(flag, "Urgent");
11647 }
11648 ast_play_and_wait(chan, "vm-msgsaved");
11649 cmd = '0';
11650 } else {
11651 ast_play_and_wait(chan, "vm-deleted");
11652 DELETE(recordfile, -1, recordfile, vmu);
11653 cmd = '0';
11654 }
11655 }
11656 return cmd;
11657 default:
11658
11659
11660
11661 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
11662 return cmd;
11663 if (msg_exists) {
11664 cmd = ast_play_and_wait(chan, "vm-review");
11665 if (!cmd && outsidecaller) {
11666 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
11667 cmd = ast_play_and_wait(chan, "vm-review-urgent");
11668 } else if (flag) {
11669 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
11670 }
11671 }
11672 } else {
11673 cmd = ast_play_and_wait(chan, "vm-torerecord");
11674 if (!cmd)
11675 cmd = ast_waitfordigit(chan, 600);
11676 }
11677
11678 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
11679 cmd = ast_play_and_wait(chan, "vm-reachoper");
11680 if (!cmd)
11681 cmd = ast_waitfordigit(chan, 600);
11682 }
11683 #if 0
11684 if (!cmd)
11685 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
11686 #endif
11687 if (!cmd)
11688 cmd = ast_waitfordigit(chan, 6000);
11689 if (!cmd) {
11690 attempts++;
11691 }
11692 if (attempts > max_attempts) {
11693 cmd = 't';
11694 }
11695 }
11696 }
11697 if (outsidecaller)
11698 ast_play_and_wait(chan, "vm-goodbye");
11699 if (cmd == 't')
11700 cmd = 0;
11701 return cmd;
11702 }
11703
11704
11705
11706
11707
11708 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
11709 .load = load_module,
11710 .unload = unload_module,
11711 .reload = reload,
11712 );