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