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