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