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