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