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 #include "asterisk.h"
00047
00048 #ifdef IMAP_STORAGE
00049 #include <ctype.h>
00050 #include <signal.h>
00051 #include <pwd.h>
00052 #ifdef USE_SYSTEM_IMAP
00053 #include <imap/c-client.h>
00054 #include <imap/imap4r1.h>
00055 #include <imap/linkage.h>
00056 #elif defined (USE_SYSTEM_CCLIENT)
00057 #include <c-client/c-client.h>
00058 #include <c-client/imap4r1.h>
00059 #include <c-client/linkage.h>
00060 #else
00061 #include "c-client.h"
00062 #include "imap4r1.h"
00063 #include "linkage.h"
00064 #endif
00065 #endif
00066
00067 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369652 $")
00068
00069 #include "asterisk/paths.h"
00070 #include <sys/time.h>
00071 #include <sys/stat.h>
00072 #include <sys/mman.h>
00073 #include <time.h>
00074 #include <dirent.h>
00075 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00076 #include <sys/wait.h>
00077 #endif
00078
00079 #include "asterisk/logger.h"
00080 #include "asterisk/lock.h"
00081 #include "asterisk/file.h"
00082 #include "asterisk/channel.h"
00083 #include "asterisk/pbx.h"
00084 #include "asterisk/config.h"
00085 #include "asterisk/say.h"
00086 #include "asterisk/module.h"
00087 #include "asterisk/adsi.h"
00088 #include "asterisk/app.h"
00089 #include "asterisk/manager.h"
00090 #include "asterisk/dsp.h"
00091 #include "asterisk/localtime.h"
00092 #include "asterisk/cli.h"
00093 #include "asterisk/utils.h"
00094 #include "asterisk/stringfields.h"
00095 #include "asterisk/smdi.h"
00096 #include "asterisk/astobj2.h"
00097 #include "asterisk/event.h"
00098 #include "asterisk/taskprocessor.h"
00099 #include "asterisk/test.h"
00100
00101 #ifdef ODBC_STORAGE
00102 #include "asterisk/res_odbc.h"
00103 #endif
00104
00105 #ifdef IMAP_STORAGE
00106 #include "asterisk/threadstorage.h"
00107 #endif
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
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
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 #ifdef IMAP_STORAGE
00348 static char imapserver[48];
00349 static char imapport[8];
00350 static char imapflags[128];
00351 static char imapfolder[64];
00352 static char imapparentfolder[64] = "\0";
00353 static char greetingfolder[64];
00354 static char authuser[32];
00355 static char authpassword[42];
00356 static int imapversion = 1;
00357
00358 static int expungeonhangup = 1;
00359 static int imapgreetings = 0;
00360 static char delimiter = '\0';
00361
00362 struct vm_state;
00363 struct ast_vm_user;
00364
00365 AST_THREADSTORAGE(ts_vmstate);
00366
00367
00368 static int init_mailstream(struct vm_state *vms, int box);
00369 static void write_file(char *filename, char *buffer, unsigned long len);
00370 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00371 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00372 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00373 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00374 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00375 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00376 static void vmstate_insert(struct vm_state *vms);
00377 static void vmstate_delete(struct vm_state *vms);
00378 static void set_update(MAILSTREAM * stream);
00379 static void init_vm_state(struct vm_state *vms);
00380 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00381 static void get_mailbox_delimiter(MAILSTREAM *stream);
00382 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00383 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00384 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);
00385 static void update_messages_by_imapuser(const char *user, unsigned long number);
00386 static int vm_delete(char *file);
00387
00388 static int imap_remove_file (char *dir, int msgnum);
00389 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00390 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00391 static void check_quota(struct vm_state *vms, char *mailbox);
00392 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00393 struct vmstate {
00394 struct vm_state *vms;
00395 AST_LIST_ENTRY(vmstate) list;
00396 };
00397
00398 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00399
00400 #endif
00401
00402 #define SMDI_MWI_WAIT_TIMEOUT 1000
00403
00404 #define COMMAND_TIMEOUT 5000
00405
00406 #define VOICEMAIL_DIR_MODE 0777
00407 #define VOICEMAIL_FILE_MODE 0666
00408 #define CHUNKSIZE 65536
00409
00410 #define VOICEMAIL_CONFIG "voicemail.conf"
00411 #define ASTERISK_USERNAME "asterisk"
00412
00413
00414
00415
00416 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00417 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00418 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00419 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00420 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00421 #define VALID_DTMF "1234567890*#"
00422
00423
00424
00425 #define SENDMAIL "/usr/sbin/sendmail -t"
00426
00427 #define INTRO "vm-intro"
00428
00429 #define MAXMSG 100
00430 #define MAXMSGLIMIT 9999
00431
00432 #define MINPASSWORD 0
00433
00434 #define BASELINELEN 72
00435 #define BASEMAXINLINE 256
00436 #ifdef IMAP_STORAGE
00437 #define ENDL "\r\n"
00438 #else
00439 #define ENDL "\n"
00440 #endif
00441
00442 #define MAX_DATETIME_FORMAT 512
00443 #define MAX_NUM_CID_CONTEXTS 10
00444
00445 #define VM_REVIEW (1 << 0)
00446 #define VM_OPERATOR (1 << 1)
00447 #define VM_SAYCID (1 << 2)
00448 #define VM_SVMAIL (1 << 3)
00449 #define VM_ENVELOPE (1 << 4)
00450 #define VM_SAYDURATION (1 << 5)
00451 #define VM_SKIPAFTERCMD (1 << 6)
00452 #define VM_FORCENAME (1 << 7)
00453 #define VM_FORCEGREET (1 << 8)
00454 #define VM_PBXSKIP (1 << 9)
00455 #define VM_DIRECFORWARD (1 << 10)
00456 #define VM_ATTACH (1 << 11)
00457 #define VM_DELETE (1 << 12)
00458 #define VM_ALLOCED (1 << 13)
00459 #define VM_SEARCH (1 << 14)
00460 #define VM_TEMPGREETWARN (1 << 15)
00461 #define VM_MOVEHEARD (1 << 16)
00462 #define VM_MESSAGEWRAP (1 << 17)
00463 #define VM_FWDURGAUTO (1 << 18)
00464 #define ERROR_LOCK_PATH -100
00465 #define OPERATOR_EXIT 300
00466
00467
00468 enum vm_box {
00469 NEW_FOLDER,
00470 OLD_FOLDER,
00471 WORK_FOLDER,
00472 FAMILY_FOLDER,
00473 FRIENDS_FOLDER,
00474 GREETINGS_FOLDER
00475 };
00476
00477 enum vm_option_flags {
00478 OPT_SILENT = (1 << 0),
00479 OPT_BUSY_GREETING = (1 << 1),
00480 OPT_UNAVAIL_GREETING = (1 << 2),
00481 OPT_RECORDGAIN = (1 << 3),
00482 OPT_PREPEND_MAILBOX = (1 << 4),
00483 OPT_AUTOPLAY = (1 << 6),
00484 OPT_DTMFEXIT = (1 << 7),
00485 OPT_MESSAGE_Urgent = (1 << 8),
00486 OPT_MESSAGE_PRIORITY = (1 << 9)
00487 };
00488
00489 enum vm_option_args {
00490 OPT_ARG_RECORDGAIN = 0,
00491 OPT_ARG_PLAYFOLDER = 1,
00492 OPT_ARG_DTMFEXIT = 2,
00493
00494 OPT_ARG_ARRAY_SIZE = 3,
00495 };
00496
00497 enum vm_passwordlocation {
00498 OPT_PWLOC_VOICEMAILCONF = 0,
00499 OPT_PWLOC_SPOOLDIR = 1,
00500 OPT_PWLOC_USERSCONF = 2,
00501 };
00502
00503 AST_APP_OPTIONS(vm_app_options, {
00504 AST_APP_OPTION('s', OPT_SILENT),
00505 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00506 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00507 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00508 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00509 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00510 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00511 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00512 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00513 });
00514
00515 static int load_config(int reload);
00516 #ifdef TEST_FRAMEWORK
00517 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00518 #endif
00519 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
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
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 struct baseio {
00605 int iocp;
00606 int iolen;
00607 int linelength;
00608 int ateof;
00609 unsigned char iobuf[BASEMAXINLINE];
00610 };
00611
00612
00613
00614 struct ast_vm_user {
00615 char context[AST_MAX_CONTEXT];
00616 char mailbox[AST_MAX_EXTENSION];
00617 char password[80];
00618 char fullname[80];
00619 char email[80];
00620 char *emailsubject;
00621 char *emailbody;
00622 char pager[80];
00623 char serveremail[80];
00624 char mailcmd[160];
00625 char language[MAX_LANGUAGE];
00626 char zonetag[80];
00627 char locale[20];
00628 char callback[80];
00629 char dialout[80];
00630 char uniqueid[80];
00631 char exit[80];
00632 char attachfmt[20];
00633 unsigned int flags;
00634 int saydurationm;
00635 int minsecs;
00636 int maxmsg;
00637 int maxdeletedmsg;
00638 int maxsecs;
00639 int passwordlocation;
00640 #ifdef IMAP_STORAGE
00641 char imapuser[80];
00642 char imappassword[80];
00643 char imapfolder[64];
00644 char imapvmshareid[80];
00645 int imapversion;
00646 #endif
00647 double volgain;
00648 AST_LIST_ENTRY(ast_vm_user) list;
00649 };
00650
00651
00652 struct vm_zone {
00653 AST_LIST_ENTRY(vm_zone) list;
00654 char name[80];
00655 char timezone[80];
00656 char msg_format[512];
00657 };
00658
00659 #define VMSTATE_MAX_MSG_ARRAY 256
00660
00661
00662 struct vm_state {
00663 char curbox[80];
00664 char username[80];
00665 char context[80];
00666 char curdir[PATH_MAX];
00667 char vmbox[PATH_MAX];
00668 char fn[PATH_MAX];
00669 char intro[PATH_MAX];
00670 int *deleted;
00671 int *heard;
00672 int dh_arraysize;
00673 int curmsg;
00674 int lastmsg;
00675 int newmessages;
00676 int oldmessages;
00677 int urgentmessages;
00678 int starting;
00679 int repeats;
00680 #ifdef IMAP_STORAGE
00681 ast_mutex_t lock;
00682 int updated;
00683 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00684 MAILSTREAM *mailstream;
00685 int vmArrayIndex;
00686 char imapuser[80];
00687 char imapfolder[64];
00688 int imapversion;
00689 int interactive;
00690 char introfn[PATH_MAX];
00691 unsigned int quota_limit;
00692 unsigned int quota_usage;
00693 struct vm_state *persist_vms;
00694 #endif
00695 };
00696
00697 #ifdef ODBC_STORAGE
00698 static char odbc_database[80];
00699 static char odbc_table[80];
00700 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00701 #define DISPOSE(a,b) remove_file(a,b)
00702 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00703 #define EXISTS(a,b,c,d) (message_exists(a,b))
00704 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00705 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00706 #define DELETE(a,b,c,d) (delete_file(a,b))
00707 #else
00708 #ifdef IMAP_STORAGE
00709 #define DISPOSE(a,b) (imap_remove_file(a,b))
00710 #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))
00711 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00712 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00713 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00714 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00715 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00716 #else
00717 #define RETRIEVE(a,b,c,d)
00718 #define DISPOSE(a,b)
00719 #define STORE(a,b,c,d,e,f,g,h,i,j)
00720 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00721 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00722 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00723 #define DELETE(a,b,c,d) (vm_delete(c))
00724 #endif
00725 #endif
00726
00727 static char VM_SPOOL_DIR[PATH_MAX];
00728
00729 static char ext_pass_cmd[128];
00730 static char ext_pass_check_cmd[128];
00731
00732 static int my_umask;
00733
00734 #define PWDCHANGE_INTERNAL (1 << 1)
00735 #define PWDCHANGE_EXTERNAL (1 << 2)
00736 static int pwdchange = PWDCHANGE_INTERNAL;
00737
00738 #ifdef ODBC_STORAGE
00739 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00740 #else
00741 # ifdef IMAP_STORAGE
00742 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00743 # else
00744 # define tdesc "Comedian Mail (Voicemail System)"
00745 # endif
00746 #endif
00747
00748 static char userscontext[AST_MAX_EXTENSION] = "default";
00749
00750 static char *addesc = "Comedian Mail";
00751
00752
00753 static char *app = "VoiceMail";
00754
00755
00756 static char *app2 = "VoiceMailMain";
00757
00758 static char *app3 = "MailboxExists";
00759 static char *app4 = "VMAuthenticate";
00760
00761 static char *sayname_app = "VMSayName";
00762
00763 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00764 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00765 static char zonetag[80];
00766 static char locale[20];
00767 static int maxsilence;
00768 static int maxmsg;
00769 static int maxdeletedmsg;
00770 static int silencethreshold = 128;
00771 static char serveremail[80];
00772 static char mailcmd[160];
00773 static char externnotify[160];
00774 static struct ast_smdi_interface *smdi_iface = NULL;
00775 static char vmfmts[80];
00776 static double volgain;
00777 static int vmminsecs;
00778 static int vmmaxsecs;
00779 static int maxgreet;
00780 static int skipms;
00781 static int maxlogins;
00782 static int minpassword;
00783 static int passwordlocation;
00784
00785
00786
00787 static unsigned int poll_mailboxes;
00788
00789
00790 static unsigned int poll_freq;
00791
00792 #define DEFAULT_POLL_FREQ 30
00793
00794 AST_MUTEX_DEFINE_STATIC(poll_lock);
00795 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00796 static pthread_t poll_thread = AST_PTHREADT_NULL;
00797 static unsigned char poll_thread_run;
00798
00799
00800 static struct ast_event_sub *mwi_sub_sub;
00801
00802 static struct ast_event_sub *mwi_unsub_sub;
00803
00804
00805
00806
00807
00808
00809
00810
00811 struct mwi_sub {
00812 AST_RWLIST_ENTRY(mwi_sub) entry;
00813 int old_urgent;
00814 int old_new;
00815 int old_old;
00816 uint32_t uniqueid;
00817 char mailbox[1];
00818 };
00819
00820 struct mwi_sub_task {
00821 const char *mailbox;
00822 const char *context;
00823 uint32_t uniqueid;
00824 };
00825
00826 static struct ast_taskprocessor *mwi_subscription_tps;
00827
00828 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00829
00830
00831 static char listen_control_forward_key[12];
00832 static char listen_control_reverse_key[12];
00833 static char listen_control_pause_key[12];
00834 static char listen_control_restart_key[12];
00835 static char listen_control_stop_key[12];
00836
00837
00838 static char vm_password[80] = "vm-password";
00839 static char vm_newpassword[80] = "vm-newpassword";
00840 static char vm_passchanged[80] = "vm-passchanged";
00841 static char vm_reenterpassword[80] = "vm-reenterpassword";
00842 static char vm_mismatch[80] = "vm-mismatch";
00843 static char vm_invalid_password[80] = "vm-invalid-password";
00844 static char vm_pls_try_again[80] = "vm-pls-try-again";
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856 static char vm_prepend_timeout[80] = "vm-then-pound";
00857
00858 static struct ast_flags globalflags = {0};
00859
00860 static int saydurationminfo;
00861
00862 static char dialcontext[AST_MAX_CONTEXT] = "";
00863 static char callcontext[AST_MAX_CONTEXT] = "";
00864 static char exitcontext[AST_MAX_CONTEXT] = "";
00865
00866 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00867
00868
00869 static char *emailbody = NULL;
00870 static char *emailsubject = NULL;
00871 static char *pagerbody = NULL;
00872 static char *pagersubject = NULL;
00873 static char fromstring[100];
00874 static char pagerfromstring[100];
00875 static char charset[32] = "ISO-8859-1";
00876
00877 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00878 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00879 static int adsiver = 1;
00880 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00881 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00882
00883
00884 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00885 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);
00886 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00887 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00888 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00889 signed char record_gain, struct vm_state *vms, char *flag);
00890 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00891 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00892 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);
00893 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);
00894 static void apply_options(struct ast_vm_user *vmu, const char *options);
00895 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);
00896 static int is_valid_dtmf(const char *key);
00897 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00898 static int write_password_to_file(const char *secretfn, const char *password);
00899 static const char *substitute_escapes(const char *value);
00900 static void free_user(struct ast_vm_user *vmu);
00901
00902 struct ao2_container *inprocess_container;
00903
00904 struct inprocess {
00905 int count;
00906 char *context;
00907 char mailbox[0];
00908 };
00909
00910 static int inprocess_hash_fn(const void *obj, const int flags)
00911 {
00912 const struct inprocess *i = obj;
00913 return atoi(i->mailbox);
00914 }
00915
00916 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00917 {
00918 struct inprocess *i = obj, *j = arg;
00919 if (strcmp(i->mailbox, j->mailbox)) {
00920 return 0;
00921 }
00922 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00923 }
00924
00925 static int inprocess_count(const char *context, const char *mailbox, int delta)
00926 {
00927 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00928 arg->context = arg->mailbox + strlen(mailbox) + 1;
00929 strcpy(arg->mailbox, mailbox);
00930 strcpy(arg->context, context);
00931 ao2_lock(inprocess_container);
00932 if ((i = ao2_find(inprocess_container, arg, 0))) {
00933 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00934 ao2_unlock(inprocess_container);
00935 ao2_ref(i, -1);
00936 return ret;
00937 }
00938 if (delta < 0) {
00939 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00940 }
00941 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00942 ao2_unlock(inprocess_container);
00943 return 0;
00944 }
00945 i->context = i->mailbox + strlen(mailbox) + 1;
00946 strcpy(i->mailbox, mailbox);
00947 strcpy(i->context, context);
00948 i->count = delta;
00949 ao2_link(inprocess_container, i);
00950 ao2_unlock(inprocess_container);
00951 ao2_ref(i, -1);
00952 return 0;
00953 }
00954
00955 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00956 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00957 #endif
00958
00959
00960
00961
00962
00963
00964
00965 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00966 {
00967 char *bufptr = buf;
00968 for (; *input; input++) {
00969 if (*input < 32) {
00970 continue;
00971 }
00972 *bufptr++ = *input;
00973 if (bufptr == buf + buflen - 1) {
00974 break;
00975 }
00976 }
00977 *bufptr = '\0';
00978 return buf;
00979 }
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995 static void populate_defaults(struct ast_vm_user *vmu)
00996 {
00997 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00998 vmu->passwordlocation = passwordlocation;
00999 if (saydurationminfo) {
01000 vmu->saydurationm = saydurationminfo;
01001 }
01002 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01003 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01004 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01005 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01006 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01007 if (vmminsecs) {
01008 vmu->minsecs = vmminsecs;
01009 }
01010 if (vmmaxsecs) {
01011 vmu->maxsecs = vmmaxsecs;
01012 }
01013 if (maxmsg) {
01014 vmu->maxmsg = maxmsg;
01015 }
01016 if (maxdeletedmsg) {
01017 vmu->maxdeletedmsg = maxdeletedmsg;
01018 }
01019 vmu->volgain = volgain;
01020 ast_free(vmu->emailsubject);
01021 vmu->emailsubject = NULL;
01022 ast_free(vmu->emailbody);
01023 vmu->emailbody = NULL;
01024 #ifdef IMAP_STORAGE
01025 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01026 #endif
01027 }
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01038 {
01039 int x;
01040 if (!strcasecmp(var, "attach")) {
01041 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01042 } else if (!strcasecmp(var, "attachfmt")) {
01043 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01044 } else if (!strcasecmp(var, "serveremail")) {
01045 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01046 } else if (!strcasecmp(var, "emailbody")) {
01047 vmu->emailbody = ast_strdup(substitute_escapes(value));
01048 } else if (!strcasecmp(var, "emailsubject")) {
01049 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01050 } else if (!strcasecmp(var, "language")) {
01051 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01052 } else if (!strcasecmp(var, "tz")) {
01053 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01054 } else if (!strcasecmp(var, "locale")) {
01055 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01056 #ifdef IMAP_STORAGE
01057 } else if (!strcasecmp(var, "imapuser")) {
01058 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01059 vmu->imapversion = imapversion;
01060 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01061 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01062 vmu->imapversion = imapversion;
01063 } else if (!strcasecmp(var, "imapfolder")) {
01064 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01065 } else if (!strcasecmp(var, "imapvmshareid")) {
01066 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01067 vmu->imapversion = imapversion;
01068 #endif
01069 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01070 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01071 } else if (!strcasecmp(var, "saycid")){
01072 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01073 } else if (!strcasecmp(var, "sendvoicemail")){
01074 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01075 } else if (!strcasecmp(var, "review")){
01076 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01077 } else if (!strcasecmp(var, "tempgreetwarn")){
01078 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01079 } else if (!strcasecmp(var, "messagewrap")){
01080 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01081 } else if (!strcasecmp(var, "operator")) {
01082 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01083 } else if (!strcasecmp(var, "envelope")){
01084 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01085 } else if (!strcasecmp(var, "moveheard")){
01086 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01087 } else if (!strcasecmp(var, "sayduration")){
01088 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01089 } else if (!strcasecmp(var, "saydurationm")){
01090 if (sscanf(value, "%30d", &x) == 1) {
01091 vmu->saydurationm = x;
01092 } else {
01093 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01094 }
01095 } else if (!strcasecmp(var, "forcename")){
01096 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01097 } else if (!strcasecmp(var, "forcegreetings")){
01098 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01099 } else if (!strcasecmp(var, "callback")) {
01100 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01101 } else if (!strcasecmp(var, "dialout")) {
01102 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01103 } else if (!strcasecmp(var, "exitcontext")) {
01104 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01105 } else if (!strcasecmp(var, "minsecs")) {
01106 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01107 vmu->minsecs = x;
01108 } else {
01109 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01110 vmu->minsecs = vmminsecs;
01111 }
01112 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01113 vmu->maxsecs = atoi(value);
01114 if (vmu->maxsecs <= 0) {
01115 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01116 vmu->maxsecs = vmmaxsecs;
01117 } else {
01118 vmu->maxsecs = atoi(value);
01119 }
01120 if (!strcasecmp(var, "maxmessage"))
01121 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01122 } else if (!strcasecmp(var, "maxmsg")) {
01123 vmu->maxmsg = atoi(value);
01124
01125 if (vmu->maxmsg < 0) {
01126 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01127 vmu->maxmsg = MAXMSG;
01128 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01129 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01130 vmu->maxmsg = MAXMSGLIMIT;
01131 }
01132 } else if (!strcasecmp(var, "nextaftercmd")) {
01133 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01134 } else if (!strcasecmp(var, "backupdeleted")) {
01135 if (sscanf(value, "%30d", &x) == 1)
01136 vmu->maxdeletedmsg = x;
01137 else if (ast_true(value))
01138 vmu->maxdeletedmsg = MAXMSG;
01139 else
01140 vmu->maxdeletedmsg = 0;
01141
01142 if (vmu->maxdeletedmsg < 0) {
01143 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01144 vmu->maxdeletedmsg = MAXMSG;
01145 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01146 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01147 vmu->maxdeletedmsg = MAXMSGLIMIT;
01148 }
01149 } else if (!strcasecmp(var, "volgain")) {
01150 sscanf(value, "%30lf", &vmu->volgain);
01151 } else if (!strcasecmp(var, "passwordlocation")) {
01152 if (!strcasecmp(value, "spooldir")) {
01153 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01154 } else {
01155 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01156 }
01157 } else if (!strcasecmp(var, "options")) {
01158 apply_options(vmu, value);
01159 }
01160 }
01161
01162 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01163 {
01164 int fds[2], pid = 0;
01165
01166 memset(buf, 0, len);
01167
01168 if (pipe(fds)) {
01169 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01170 } else {
01171
01172 pid = ast_safe_fork(0);
01173
01174 if (pid < 0) {
01175
01176 close(fds[0]);
01177 close(fds[1]);
01178 snprintf(buf, len, "FAILURE: Fork failed");
01179 } else if (pid) {
01180
01181 close(fds[1]);
01182 if (read(fds[0], buf, len) < 0) {
01183 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01184 }
01185 close(fds[0]);
01186 } else {
01187
01188 AST_DECLARE_APP_ARGS(arg,
01189 AST_APP_ARG(v)[20];
01190 );
01191 char *mycmd = ast_strdupa(command);
01192
01193 close(fds[0]);
01194 dup2(fds[1], STDOUT_FILENO);
01195 close(fds[1]);
01196 ast_close_fds_above_n(STDOUT_FILENO);
01197
01198 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01199
01200 execv(arg.v[0], arg.v);
01201 printf("FAILURE: %s", strerror(errno));
01202 _exit(0);
01203 }
01204 }
01205 return buf;
01206 }
01207
01208
01209
01210
01211
01212
01213
01214
01215 static int check_password(struct ast_vm_user *vmu, char *password)
01216 {
01217
01218 if (strlen(password) < minpassword)
01219 return 1;
01220
01221 if (!ast_strlen_zero(password) && password[0] == '*')
01222 return 1;
01223 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01224 char cmd[255], buf[255];
01225
01226 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01227
01228 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01229 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01230 ast_debug(5, "Result: %s\n", buf);
01231 if (!strncasecmp(buf, "VALID", 5)) {
01232 ast_debug(3, "Passed password check: '%s'\n", buf);
01233 return 0;
01234 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01235 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01236 return 0;
01237 } else {
01238 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01239 return 1;
01240 }
01241 }
01242 }
01243 return 0;
01244 }
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01257 {
01258 int res = -1;
01259 if (!strcmp(vmu->password, password)) {
01260
01261 return 0;
01262 }
01263
01264 if (strlen(password) > 10) {
01265 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01266 }
01267 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01268 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01269 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01270 res = 0;
01271 }
01272 return res;
01273 }
01274
01275
01276
01277
01278 static void apply_options(struct ast_vm_user *vmu, const char *options)
01279 {
01280 char *stringp;
01281 char *s;
01282 char *var, *value;
01283 stringp = ast_strdupa(options);
01284 while ((s = strsep(&stringp, "|"))) {
01285 value = s;
01286 if ((var = strsep(&value, "=")) && value) {
01287 apply_option(vmu, var, value);
01288 }
01289 }
01290 }
01291
01292
01293
01294
01295
01296
01297 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01298 {
01299 for (; var; var = var->next) {
01300 if (!strcasecmp(var->name, "vmsecret")) {
01301 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01302 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01303 if (ast_strlen_zero(retval->password)) {
01304 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01305 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01306 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01307 } else {
01308 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01309 }
01310 }
01311 } else if (!strcasecmp(var->name, "uniqueid")) {
01312 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01313 } else if (!strcasecmp(var->name, "pager")) {
01314 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01315 } else if (!strcasecmp(var->name, "email")) {
01316 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01317 } else if (!strcasecmp(var->name, "fullname")) {
01318 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01319 } else if (!strcasecmp(var->name, "context")) {
01320 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01321 } else if (!strcasecmp(var->name, "emailsubject")) {
01322 ast_free(retval->emailsubject);
01323 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01324 } else if (!strcasecmp(var->name, "emailbody")) {
01325 ast_free(retval->emailbody);
01326 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01327 #ifdef IMAP_STORAGE
01328 } else if (!strcasecmp(var->name, "imapuser")) {
01329 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01330 retval->imapversion = imapversion;
01331 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01332 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01333 retval->imapversion = imapversion;
01334 } else if (!strcasecmp(var->name, "imapfolder")) {
01335 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01336 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01337 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01338 retval->imapversion = imapversion;
01339 #endif
01340 } else
01341 apply_option(retval, var->name, var->value);
01342 }
01343 }
01344
01345
01346
01347
01348
01349
01350
01351
01352 static int is_valid_dtmf(const char *key)
01353 {
01354 int i;
01355 char *local_key = ast_strdupa(key);
01356
01357 for (i = 0; i < strlen(key); ++i) {
01358 if (!strchr(VALID_DTMF, *local_key)) {
01359 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01360 return 0;
01361 }
01362 local_key++;
01363 }
01364 return 1;
01365 }
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01378 {
01379 struct ast_variable *var;
01380 struct ast_vm_user *retval;
01381
01382 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01383 if (!ivm)
01384 ast_set_flag(retval, VM_ALLOCED);
01385 else
01386 memset(retval, 0, sizeof(*retval));
01387 if (mailbox)
01388 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01389 populate_defaults(retval);
01390 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01391 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01392 else
01393 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01394 if (var) {
01395 apply_options_full(retval, var);
01396 ast_variables_destroy(var);
01397 } else {
01398 if (!ivm)
01399 free_user(retval);
01400 retval = NULL;
01401 }
01402 }
01403 return retval;
01404 }
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01415 {
01416
01417 struct ast_vm_user *vmu = NULL, *cur;
01418 AST_LIST_LOCK(&users);
01419
01420 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01421 context = "default";
01422
01423 AST_LIST_TRAVERSE(&users, cur, list) {
01424 #ifdef IMAP_STORAGE
01425 if (cur->imapversion != imapversion) {
01426 continue;
01427 }
01428 #endif
01429 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01430 break;
01431 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01432 break;
01433 }
01434 if (cur) {
01435
01436 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01437 *vmu = *cur;
01438 if (!ivm) {
01439 vmu->emailbody = ast_strdup(cur->emailbody);
01440 vmu->emailsubject = ast_strdup(cur->emailsubject);
01441 }
01442 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01443 AST_LIST_NEXT(vmu, list) = NULL;
01444 }
01445 } else
01446 vmu = find_user_realtime(ivm, context, mailbox);
01447 AST_LIST_UNLOCK(&users);
01448 return vmu;
01449 }
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01462 {
01463
01464 struct ast_vm_user *cur;
01465 int res = -1;
01466 AST_LIST_LOCK(&users);
01467 AST_LIST_TRAVERSE(&users, cur, list) {
01468 if ((!context || !strcasecmp(context, cur->context)) &&
01469 (!strcasecmp(mailbox, cur->mailbox)))
01470 break;
01471 }
01472 if (cur) {
01473 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01474 res = 0;
01475 }
01476 AST_LIST_UNLOCK(&users);
01477 return res;
01478 }
01479
01480
01481
01482
01483
01484
01485
01486
01487 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01488 {
01489 struct ast_config *cfg = NULL;
01490 struct ast_variable *var = NULL;
01491 struct ast_category *cat = NULL;
01492 char *category = NULL, *value = NULL, *new = NULL;
01493 const char *tmp = NULL;
01494 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01495 char secretfn[PATH_MAX] = "";
01496 int found = 0;
01497
01498 if (!change_password_realtime(vmu, newpassword))
01499 return;
01500
01501
01502 switch (vmu->passwordlocation) {
01503 case OPT_PWLOC_SPOOLDIR:
01504 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01505 if (write_password_to_file(secretfn, newpassword) == 0) {
01506 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01507 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01508 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01509 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01510 break;
01511 } else {
01512 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01513 }
01514
01515 case OPT_PWLOC_VOICEMAILCONF:
01516 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01517 while ((category = ast_category_browse(cfg, category))) {
01518 if (!strcasecmp(category, vmu->context)) {
01519 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01520 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01521 break;
01522 }
01523 value = strstr(tmp, ",");
01524 if (!value) {
01525 new = alloca(strlen(newpassword)+1);
01526 sprintf(new, "%s", newpassword);
01527 } else {
01528 new = alloca((strlen(value) + strlen(newpassword) + 1));
01529 sprintf(new, "%s%s", newpassword, value);
01530 }
01531 if (!(cat = ast_category_get(cfg, category))) {
01532 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01533 break;
01534 }
01535 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01536 found = 1;
01537 }
01538 }
01539
01540 if (found) {
01541 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01542 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01543 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01544 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01545 break;
01546 }
01547 }
01548
01549 case OPT_PWLOC_USERSCONF:
01550
01551
01552 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01553 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01554 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01555 ast_debug(4, "users.conf: %s\n", category);
01556 if (!strcasecmp(category, vmu->mailbox)) {
01557 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01558 ast_debug(3, "looks like we need to make vmsecret!\n");
01559 var = ast_variable_new("vmsecret", newpassword, "");
01560 } else {
01561 var = NULL;
01562 }
01563 new = alloca(strlen(newpassword) + 1);
01564 sprintf(new, "%s", newpassword);
01565 if (!(cat = ast_category_get(cfg, category))) {
01566 ast_debug(4, "failed to get category!\n");
01567 ast_free(var);
01568 break;
01569 }
01570 if (!var) {
01571 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01572 } else {
01573 ast_variable_append(cat, var);
01574 }
01575 found = 1;
01576 break;
01577 }
01578 }
01579
01580 if (found) {
01581 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01582 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01583 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01584 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01585 }
01586 }
01587 }
01588 }
01589
01590 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01591 {
01592 char buf[255];
01593 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01594 ast_debug(1, "External password: %s\n",buf);
01595 if (!ast_safe_system(buf)) {
01596 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01597 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01598
01599 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01600 }
01601 }
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01617 {
01618 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01619 }
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633 static int make_file(char *dest, const int len, const char *dir, const int num)
01634 {
01635 return snprintf(dest, len, "%s/msg%04d", dir, num);
01636 }
01637
01638
01639 static FILE *vm_mkftemp(char *template)
01640 {
01641 FILE *p = NULL;
01642 int pfd = mkstemp(template);
01643 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01644 if (pfd > -1) {
01645 p = fdopen(pfd, "w+");
01646 if (!p) {
01647 close(pfd);
01648 pfd = -1;
01649 }
01650 }
01651 return p;
01652 }
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01663 {
01664 mode_t mode = VOICEMAIL_DIR_MODE;
01665 int res;
01666
01667 make_dir(dest, len, context, ext, folder);
01668 if ((res = ast_mkdir(dest, mode))) {
01669 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01670 return -1;
01671 }
01672 return 0;
01673 }
01674
01675 static const char * const mailbox_folders[] = {
01676 #ifdef IMAP_STORAGE
01677 imapfolder,
01678 #else
01679 "INBOX",
01680 #endif
01681 "Old",
01682 "Work",
01683 "Family",
01684 "Friends",
01685 "Cust1",
01686 "Cust2",
01687 "Cust3",
01688 "Cust4",
01689 "Cust5",
01690 "Deleted",
01691 "Urgent",
01692 };
01693
01694 static const char *mbox(struct ast_vm_user *vmu, int id)
01695 {
01696 #ifdef IMAP_STORAGE
01697 if (vmu && id == 0) {
01698 return vmu->imapfolder;
01699 }
01700 #endif
01701 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01702 }
01703
01704 static int get_folder_by_name(const char *name)
01705 {
01706 size_t i;
01707
01708 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01709 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01710 return i;
01711 }
01712 }
01713
01714 return -1;
01715 }
01716
01717 static void free_user(struct ast_vm_user *vmu)
01718 {
01719 if (ast_test_flag(vmu, VM_ALLOCED)) {
01720
01721 ast_free(vmu->emailbody);
01722 vmu->emailbody = NULL;
01723
01724 ast_free(vmu->emailsubject);
01725 vmu->emailsubject = NULL;
01726
01727 ast_free(vmu);
01728 }
01729 }
01730
01731 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01732
01733 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01734
01735
01736 if (vms->deleted) {
01737 ast_free(vms->deleted);
01738 vms->deleted = NULL;
01739 }
01740 if (vms->heard) {
01741 ast_free(vms->heard);
01742 vms->heard = NULL;
01743 }
01744 vms->dh_arraysize = 0;
01745
01746 if (arraysize > 0) {
01747 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01748 return -1;
01749 }
01750 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01751 ast_free(vms->deleted);
01752 vms->deleted = NULL;
01753 return -1;
01754 }
01755 vms->dh_arraysize = arraysize;
01756 }
01757
01758 return 0;
01759 }
01760
01761
01762
01763 #ifdef IMAP_STORAGE
01764 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01765 {
01766 char arg[10];
01767 struct vm_state *vms;
01768 unsigned long messageNum;
01769
01770
01771 if (msgnum < 0 && !imapgreetings) {
01772 ast_filedelete(file, NULL);
01773 return;
01774 }
01775
01776 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01777 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);
01778 return;
01779 }
01780
01781
01782
01783 messageNum = vms->msgArray[msgnum];
01784 if (messageNum == 0) {
01785 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01786 return;
01787 }
01788 if (option_debug > 2)
01789 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01790
01791 snprintf (arg, sizeof(arg), "%lu", messageNum);
01792 ast_mutex_lock(&vms->lock);
01793 mail_setflag (vms->mailstream, arg, "\\DELETED");
01794 mail_expunge(vms->mailstream);
01795 ast_mutex_unlock(&vms->lock);
01796 }
01797
01798 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01799 {
01800 struct vm_state *vms_p;
01801 char *file, *filename;
01802 char *attachment;
01803 int i;
01804 BODY *body;
01805
01806
01807
01808
01809 if (msgnum > -1 || !imapgreetings) {
01810 return 0;
01811 } else {
01812 file = strrchr(ast_strdupa(dir), '/');
01813 if (file)
01814 *file++ = '\0';
01815 else {
01816 ast_debug (1, "Failed to procure file name from directory passed.\n");
01817 return -1;
01818 }
01819 }
01820
01821
01822 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01823 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01824
01825
01826
01827
01828 if (!(vms_p = create_vm_state_from_user(vmu))) {
01829 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01830 return -1;
01831 }
01832 }
01833
01834
01835 *vms_p->introfn = '\0';
01836
01837 ast_mutex_lock(&vms_p->lock);
01838 init_mailstream(vms_p, GREETINGS_FOLDER);
01839 if (!vms_p->mailstream) {
01840 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01841 ast_mutex_unlock(&vms_p->lock);
01842 return -1;
01843 }
01844
01845
01846 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01847 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01848
01849 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01850 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01851 } else {
01852 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01853 ast_mutex_unlock(&vms_p->lock);
01854 return -1;
01855 }
01856 filename = strsep(&attachment, ".");
01857 if (!strcmp(filename, file)) {
01858 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01859 vms_p->msgArray[vms_p->curmsg] = i + 1;
01860 save_body(body, vms_p, "2", attachment, 0);
01861 ast_mutex_unlock(&vms_p->lock);
01862 return 0;
01863 }
01864 }
01865 ast_mutex_unlock(&vms_p->lock);
01866
01867 return -1;
01868 }
01869
01870 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01871 {
01872 BODY *body;
01873 char *header_content;
01874 char *attachedfilefmt;
01875 char buf[80];
01876 struct vm_state *vms;
01877 char text_file[PATH_MAX];
01878 FILE *text_file_ptr;
01879 int res = 0;
01880 struct ast_vm_user *vmu;
01881
01882 if (!(vmu = find_user(NULL, context, mailbox))) {
01883 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01884 return -1;
01885 }
01886
01887 if (msgnum < 0) {
01888 if (imapgreetings) {
01889 res = imap_retrieve_greeting(dir, msgnum, vmu);
01890 goto exit;
01891 } else {
01892 res = 0;
01893 goto exit;
01894 }
01895 }
01896
01897
01898
01899
01900 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01901
01902
01903
01904
01905
01906
01907
01908 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01909 res = -1;
01910 goto exit;
01911 }
01912
01913 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01914 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01915
01916
01917 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01918 res = 0;
01919 goto exit;
01920 }
01921
01922 if (option_debug > 2)
01923 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01924 if (vms->msgArray[msgnum] == 0) {
01925 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01926 res = -1;
01927 goto exit;
01928 }
01929
01930
01931 ast_mutex_lock(&vms->lock);
01932 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01933 ast_mutex_unlock(&vms->lock);
01934
01935 if (ast_strlen_zero(header_content)) {
01936 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01937 res = -1;
01938 goto exit;
01939 }
01940
01941 ast_mutex_lock(&vms->lock);
01942 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01943 ast_mutex_unlock(&vms->lock);
01944
01945
01946 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01947 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01948 } else {
01949 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01950 res = -1;
01951 goto exit;
01952 }
01953
01954
01955
01956 strsep(&attachedfilefmt, ".");
01957 if (!attachedfilefmt) {
01958 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01959 res = -1;
01960 goto exit;
01961 }
01962
01963 save_body(body, vms, "2", attachedfilefmt, 0);
01964 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01965 *vms->introfn = '\0';
01966 }
01967
01968
01969 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01970
01971 if (!(text_file_ptr = fopen(text_file, "w"))) {
01972 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01973 }
01974
01975 fprintf(text_file_ptr, "%s\n", "[message]");
01976
01977 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01978 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01979 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01980 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01981 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01982 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
01983 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
01984 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
01985 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
01986 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
01987 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
01988 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
01989 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
01990 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
01991 fclose(text_file_ptr);
01992
01993 exit:
01994 free_user(vmu);
01995 return res;
01996 }
01997
01998 static int folder_int(const char *folder)
01999 {
02000
02001 if (!folder) {
02002 return 0;
02003 }
02004 if (!strcasecmp(folder, imapfolder)) {
02005 return 0;
02006 } else if (!strcasecmp(folder, "Old")) {
02007 return 1;
02008 } else if (!strcasecmp(folder, "Work")) {
02009 return 2;
02010 } else if (!strcasecmp(folder, "Family")) {
02011 return 3;
02012 } else if (!strcasecmp(folder, "Friends")) {
02013 return 4;
02014 } else if (!strcasecmp(folder, "Cust1")) {
02015 return 5;
02016 } else if (!strcasecmp(folder, "Cust2")) {
02017 return 6;
02018 } else if (!strcasecmp(folder, "Cust3")) {
02019 return 7;
02020 } else if (!strcasecmp(folder, "Cust4")) {
02021 return 8;
02022 } else if (!strcasecmp(folder, "Cust5")) {
02023 return 9;
02024 } else if (!strcasecmp(folder, "Urgent")) {
02025 return 11;
02026 } else {
02027 return 0;
02028 }
02029 }
02030
02031 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02032 {
02033 SEARCHPGM *pgm;
02034 SEARCHHEADER *hdr;
02035
02036 struct ast_vm_user *vmu, vmus;
02037 struct vm_state *vms_p;
02038 int ret = 0;
02039 int fold = folder_int(folder);
02040 int urgent = 0;
02041
02042
02043 if (fold == 11) {
02044 fold = NEW_FOLDER;
02045 urgent = 1;
02046 }
02047
02048 if (ast_strlen_zero(mailbox))
02049 return 0;
02050
02051
02052 vmu = find_user(&vmus, context, mailbox);
02053 if (!vmu) {
02054 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02055 return -1;
02056 } else {
02057
02058 if (vmu->imapuser[0] == '\0') {
02059 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02060 return -1;
02061 }
02062 }
02063
02064
02065 if (vmu->imapuser[0] == '\0') {
02066 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02067 free_user(vmu);
02068 return -1;
02069 }
02070
02071
02072 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02073 if (!vms_p) {
02074 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02075 }
02076 if (vms_p) {
02077 ast_debug(3, "Returning before search - user is logged in\n");
02078 if (fold == 0) {
02079 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02080 }
02081 if (fold == 1) {
02082 return vms_p->oldmessages;
02083 }
02084 }
02085
02086
02087 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02088 if (!vms_p) {
02089 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02090 }
02091
02092 if (!vms_p) {
02093 vms_p = create_vm_state_from_user(vmu);
02094 }
02095 ret = init_mailstream(vms_p, fold);
02096 if (!vms_p->mailstream) {
02097 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02098 return -1;
02099 }
02100 if (ret == 0) {
02101 ast_mutex_lock(&vms_p->lock);
02102 pgm = mail_newsearchpgm ();
02103 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02104 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02105 pgm->header = hdr;
02106 if (fold != OLD_FOLDER) {
02107 pgm->unseen = 1;
02108 pgm->seen = 0;
02109 }
02110
02111
02112
02113 else {
02114 pgm->unseen = 0;
02115 pgm->seen = 1;
02116 }
02117
02118 if (fold == NEW_FOLDER) {
02119 if (urgent) {
02120 pgm->flagged = 1;
02121 pgm->unflagged = 0;
02122 } else {
02123 pgm->flagged = 0;
02124 pgm->unflagged = 1;
02125 }
02126 }
02127 pgm->undeleted = 1;
02128 pgm->deleted = 0;
02129
02130 vms_p->vmArrayIndex = 0;
02131 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02132 if (fold == 0 && urgent == 0)
02133 vms_p->newmessages = vms_p->vmArrayIndex;
02134 if (fold == 1)
02135 vms_p->oldmessages = vms_p->vmArrayIndex;
02136 if (fold == 0 && urgent == 1)
02137 vms_p->urgentmessages = vms_p->vmArrayIndex;
02138
02139 mail_free_searchpgm(&pgm);
02140 ast_mutex_unlock(&vms_p->lock);
02141 vms_p->updated = 0;
02142 return vms_p->vmArrayIndex;
02143 } else {
02144 ast_mutex_lock(&vms_p->lock);
02145 mail_ping(vms_p->mailstream);
02146 ast_mutex_unlock(&vms_p->lock);
02147 }
02148 return 0;
02149 }
02150
02151 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02152 {
02153
02154 check_quota(vms, vmu->imapfolder);
02155 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02156 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02157 ast_play_and_wait(chan, "vm-mailboxfull");
02158 return -1;
02159 }
02160
02161
02162 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));
02163 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02164 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02165 ast_play_and_wait(chan, "vm-mailboxfull");
02166 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02167 return -1;
02168 }
02169
02170 return 0;
02171 }
02172
02173
02174
02175
02176
02177
02178
02179
02180
02181
02182 static int messagecount(const char *context, const char *mailbox, const char *folder)
02183 {
02184 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02185 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02186 } else {
02187 return __messagecount(context, mailbox, folder);
02188 }
02189 }
02190
02191 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)
02192 {
02193 char *myserveremail = serveremail;
02194 char fn[PATH_MAX];
02195 char introfn[PATH_MAX];
02196 char mailbox[256];
02197 char *stringp;
02198 FILE *p = NULL;
02199 char tmp[80] = "/tmp/astmail-XXXXXX";
02200 long len;
02201 void *buf;
02202 int tempcopy = 0;
02203 STRING str;
02204 int ret;
02205 char *imap_flags = NIL;
02206 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02207 int box = NEW_FOLDER;
02208
02209
02210 if (msgnum < 0) {
02211 if(!imapgreetings) {
02212 return 0;
02213 } else {
02214 box = GREETINGS_FOLDER;
02215 }
02216 }
02217
02218 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02219 return -1;
02220 }
02221
02222
02223 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02224 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02225 imap_flags = "\\FLAGGED";
02226 }
02227
02228
02229 fmt = ast_strdupa(fmt);
02230 stringp = fmt;
02231 strsep(&stringp, "|");
02232
02233 if (!ast_strlen_zero(vmu->serveremail))
02234 myserveremail = vmu->serveremail;
02235
02236 if (msgnum > -1)
02237 make_file(fn, sizeof(fn), dir, msgnum);
02238 else
02239 ast_copy_string (fn, dir, sizeof(fn));
02240
02241 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02242 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02243 *introfn = '\0';
02244 }
02245
02246 if (ast_strlen_zero(vmu->email)) {
02247
02248
02249
02250
02251
02252 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02253 tempcopy = 1;
02254 }
02255
02256 if (!strcmp(fmt, "wav49"))
02257 fmt = "WAV";
02258 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02259
02260
02261
02262 if (!(p = vm_mkftemp(tmp))) {
02263 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02264 if (tempcopy)
02265 *(vmu->email) = '\0';
02266 return -1;
02267 }
02268
02269 if (msgnum < 0 && imapgreetings) {
02270 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02271 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02272 return -1;
02273 }
02274 imap_delete_old_greeting(fn, vms);
02275 }
02276
02277 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02278 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02279 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02280 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02281
02282 len = ftell(p);
02283 rewind(p);
02284 if (!(buf = ast_malloc(len + 1))) {
02285 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02286 fclose(p);
02287 if (tempcopy)
02288 *(vmu->email) = '\0';
02289 return -1;
02290 }
02291 if (fread(buf, len, 1, p) < len) {
02292 if (ferror(p)) {
02293 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02294 return -1;
02295 }
02296 }
02297 ((char *) buf)[len] = '\0';
02298 INIT(&str, mail_string, buf, len);
02299 ret = init_mailstream(vms, box);
02300 if (ret == 0) {
02301 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02302 ast_mutex_lock(&vms->lock);
02303 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02304 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02305 ast_mutex_unlock(&vms->lock);
02306 fclose(p);
02307 unlink(tmp);
02308 ast_free(buf);
02309 } else {
02310 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02311 fclose(p);
02312 unlink(tmp);
02313 ast_free(buf);
02314 return -1;
02315 }
02316 ast_debug(3, "%s stored\n", fn);
02317
02318 if (tempcopy)
02319 *(vmu->email) = '\0';
02320 inprocess_count(vmu->mailbox, vmu->context, -1);
02321 return 0;
02322
02323 }
02324
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335
02336
02337
02338 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02339 {
02340 char tmp[PATH_MAX] = "";
02341 char *mailboxnc;
02342 char *context;
02343 char *mb;
02344 char *cur;
02345 if (newmsgs)
02346 *newmsgs = 0;
02347 if (oldmsgs)
02348 *oldmsgs = 0;
02349 if (urgentmsgs)
02350 *urgentmsgs = 0;
02351
02352 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02353
02354 if (ast_strlen_zero(mailbox_context))
02355 return 0;
02356
02357 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02358 context = strchr(tmp, '@');
02359 if (strchr(mailbox_context, ',')) {
02360 int tmpnew, tmpold, tmpurgent;
02361 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02362 mb = tmp;
02363 while ((cur = strsep(&mb, ", "))) {
02364 if (!ast_strlen_zero(cur)) {
02365 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02366 return -1;
02367 else {
02368 if (newmsgs)
02369 *newmsgs += tmpnew;
02370 if (oldmsgs)
02371 *oldmsgs += tmpold;
02372 if (urgentmsgs)
02373 *urgentmsgs += tmpurgent;
02374 }
02375 }
02376 }
02377 return 0;
02378 }
02379 if (context) {
02380 *context = '\0';
02381 mailboxnc = tmp;
02382 context++;
02383 } else {
02384 context = "default";
02385 mailboxnc = (char *) mailbox_context;
02386 }
02387
02388 if (newmsgs) {
02389 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02390 if (!vmu) {
02391 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02392 return -1;
02393 }
02394 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02395 return -1;
02396 }
02397 }
02398 if (oldmsgs) {
02399 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02400 return -1;
02401 }
02402 }
02403 if (urgentmsgs) {
02404 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02405 return -1;
02406 }
02407 }
02408 return 0;
02409 }
02410
02411
02412
02413
02414
02415
02416
02417
02418
02419
02420
02421 static int has_voicemail(const char *mailbox, const char *folder)
02422 {
02423 char tmp[256], *tmp2, *box, *context;
02424 ast_copy_string(tmp, mailbox, sizeof(tmp));
02425 tmp2 = tmp;
02426 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02427 while ((box = strsep(&tmp2, ",&"))) {
02428 if (!ast_strlen_zero(box)) {
02429 if (has_voicemail(box, folder)) {
02430 return 1;
02431 }
02432 }
02433 }
02434 }
02435 if ((context = strchr(tmp, '@'))) {
02436 *context++ = '\0';
02437 } else {
02438 context = "default";
02439 }
02440 return __messagecount(context, tmp, folder) ? 1 : 0;
02441 }
02442
02443
02444
02445
02446
02447
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458 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)
02459 {
02460 struct vm_state *sendvms = NULL, *destvms = NULL;
02461 char messagestring[10];
02462 if (msgnum >= recip->maxmsg) {
02463 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02464 return -1;
02465 }
02466 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02467 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02468 return -1;
02469 }
02470 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02471 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02472 return -1;
02473 }
02474 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02475 ast_mutex_lock(&sendvms->lock);
02476 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02477 ast_mutex_unlock(&sendvms->lock);
02478 return 0;
02479 }
02480 ast_mutex_unlock(&sendvms->lock);
02481 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02482 return -1;
02483 }
02484
02485 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02486 {
02487 char tmp[256], *t = tmp;
02488 size_t left = sizeof(tmp);
02489
02490 if (box == OLD_FOLDER) {
02491 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02492 } else {
02493 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02494 }
02495
02496 if (box == NEW_FOLDER) {
02497 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02498 } else {
02499 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02500 }
02501
02502
02503 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02504
02505
02506 if (!ast_strlen_zero(authuser))
02507 ast_build_string(&t, &left, "/authuser=%s", authuser);
02508
02509
02510 if (!ast_strlen_zero(imapflags))
02511 ast_build_string(&t, &left, "/%s", imapflags);
02512
02513
02514 #if 1
02515 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02516 #else
02517 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02518 #endif
02519 if (box == NEW_FOLDER || box == OLD_FOLDER)
02520 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02521 else if (box == GREETINGS_FOLDER)
02522 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02523 else {
02524 if (!ast_strlen_zero(imapparentfolder)) {
02525
02526 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02527 } else {
02528 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02529 }
02530 }
02531 }
02532
02533 static int init_mailstream(struct vm_state *vms, int box)
02534 {
02535 MAILSTREAM *stream = NIL;
02536 long debug;
02537 char tmp[256];
02538
02539 if (!vms) {
02540 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02541 return -1;
02542 }
02543 if (option_debug > 2)
02544 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02545 if (vms->mailstream == NIL || !vms->mailstream) {
02546 if (option_debug)
02547 ast_log(LOG_DEBUG, "mailstream not set.\n");
02548 } else {
02549 stream = vms->mailstream;
02550 }
02551
02552 debug = NIL;
02553
02554 if (delimiter == '\0') {
02555 char *cp;
02556 #ifdef USE_SYSTEM_IMAP
02557 #include <imap/linkage.c>
02558 #elif defined(USE_SYSTEM_CCLIENT)
02559 #include <c-client/linkage.c>
02560 #else
02561 #include "linkage.c"
02562 #endif
02563
02564 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02565 ast_mutex_lock(&vms->lock);
02566 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02567 ast_mutex_unlock(&vms->lock);
02568 if (stream == NIL) {
02569 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02570 return -1;
02571 }
02572 get_mailbox_delimiter(stream);
02573
02574 for (cp = vms->imapfolder; *cp; cp++)
02575 if (*cp == '/')
02576 *cp = delimiter;
02577 }
02578
02579 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02580 if (option_debug > 2)
02581 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02582 ast_mutex_lock(&vms->lock);
02583 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02584 ast_mutex_unlock(&vms->lock);
02585 if (vms->mailstream == NIL) {
02586 return -1;
02587 } else {
02588 return 0;
02589 }
02590 }
02591
02592 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02593 {
02594 SEARCHPGM *pgm;
02595 SEARCHHEADER *hdr;
02596 int ret, urgent = 0;
02597
02598
02599 if (box == 11) {
02600 box = NEW_FOLDER;
02601 urgent = 1;
02602 }
02603
02604 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02605 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02606 vms->imapversion = vmu->imapversion;
02607 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02608
02609 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02610 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02611 return -1;
02612 }
02613
02614 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02615
02616
02617 if (box == 0) {
02618 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02619 check_quota(vms, (char *) mbox(vmu, box));
02620 }
02621
02622 ast_mutex_lock(&vms->lock);
02623 pgm = mail_newsearchpgm();
02624
02625
02626 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02627 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02628 pgm->header = hdr;
02629 pgm->deleted = 0;
02630 pgm->undeleted = 1;
02631
02632
02633 if (box == NEW_FOLDER && urgent == 1) {
02634 pgm->unseen = 1;
02635 pgm->seen = 0;
02636 pgm->flagged = 1;
02637 pgm->unflagged = 0;
02638 } else if (box == NEW_FOLDER && urgent == 0) {
02639 pgm->unseen = 1;
02640 pgm->seen = 0;
02641 pgm->flagged = 0;
02642 pgm->unflagged = 1;
02643 } else if (box == OLD_FOLDER) {
02644 pgm->seen = 1;
02645 pgm->unseen = 0;
02646 }
02647
02648 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02649
02650 vms->vmArrayIndex = 0;
02651 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02652 vms->lastmsg = vms->vmArrayIndex - 1;
02653 mail_free_searchpgm(&pgm);
02654
02655
02656
02657
02658 if (box == 0 && !vms->dh_arraysize) {
02659 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02660 }
02661 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02662 ast_mutex_unlock(&vms->lock);
02663 return -1;
02664 }
02665
02666 ast_mutex_unlock(&vms->lock);
02667 return 0;
02668 }
02669
02670 static void write_file(char *filename, char *buffer, unsigned long len)
02671 {
02672 FILE *output;
02673
02674 output = fopen (filename, "w");
02675 if (fwrite(buffer, len, 1, output) != 1) {
02676 if (ferror(output)) {
02677 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02678 }
02679 }
02680 fclose (output);
02681 }
02682
02683 static void update_messages_by_imapuser(const char *user, unsigned long number)
02684 {
02685 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02686
02687 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02688 return;
02689 }
02690
02691 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02692 vms->msgArray[vms->vmArrayIndex++] = number;
02693 }
02694
02695 void mm_searched(MAILSTREAM *stream, unsigned long number)
02696 {
02697 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02698
02699 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02700 return;
02701
02702 update_messages_by_imapuser(user, number);
02703 }
02704
02705 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02706 {
02707 struct ast_variable *var;
02708 struct ast_vm_user *vmu;
02709
02710 vmu = ast_calloc(1, sizeof *vmu);
02711 if (!vmu)
02712 return NULL;
02713 ast_set_flag(vmu, VM_ALLOCED);
02714 populate_defaults(vmu);
02715
02716 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02717 if (var) {
02718 apply_options_full(vmu, var);
02719 ast_variables_destroy(var);
02720 return vmu;
02721 } else {
02722 ast_free(vmu);
02723 return NULL;
02724 }
02725 }
02726
02727
02728
02729 void mm_exists(MAILSTREAM * stream, unsigned long number)
02730 {
02731
02732 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02733 if (number == 0) return;
02734 set_update(stream);
02735 }
02736
02737
02738 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02739 {
02740
02741 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02742 if (number == 0) return;
02743 set_update(stream);
02744 }
02745
02746
02747 void mm_flags(MAILSTREAM * stream, unsigned long number)
02748 {
02749
02750 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02751 if (number == 0) return;
02752 set_update(stream);
02753 }
02754
02755
02756 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02757 {
02758 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02759 mm_log (string, errflg);
02760 }
02761
02762
02763 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02764 {
02765 if (delimiter == '\0') {
02766 delimiter = delim;
02767 }
02768
02769 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02770 if (attributes & LATT_NOINFERIORS)
02771 ast_debug(5, "no inferiors\n");
02772 if (attributes & LATT_NOSELECT)
02773 ast_debug(5, "no select\n");
02774 if (attributes & LATT_MARKED)
02775 ast_debug(5, "marked\n");
02776 if (attributes & LATT_UNMARKED)
02777 ast_debug(5, "unmarked\n");
02778 }
02779
02780
02781 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02782 {
02783 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02784 if (attributes & LATT_NOINFERIORS)
02785 ast_debug(5, "no inferiors\n");
02786 if (attributes & LATT_NOSELECT)
02787 ast_debug(5, "no select\n");
02788 if (attributes & LATT_MARKED)
02789 ast_debug(5, "marked\n");
02790 if (attributes & LATT_UNMARKED)
02791 ast_debug(5, "unmarked\n");
02792 }
02793
02794
02795 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02796 {
02797 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02798 if (status->flags & SA_MESSAGES)
02799 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02800 if (status->flags & SA_RECENT)
02801 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02802 if (status->flags & SA_UNSEEN)
02803 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02804 if (status->flags & SA_UIDVALIDITY)
02805 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02806 if (status->flags & SA_UIDNEXT)
02807 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02808 ast_log(AST_LOG_NOTICE, "\n");
02809 }
02810
02811
02812 void mm_log(char *string, long errflg)
02813 {
02814 switch ((short) errflg) {
02815 case NIL:
02816 ast_debug(1, "IMAP Info: %s\n", string);
02817 break;
02818 case PARSE:
02819 case WARN:
02820 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02821 break;
02822 case ERROR:
02823 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02824 break;
02825 }
02826 }
02827
02828
02829 void mm_dlog(char *string)
02830 {
02831 ast_log(AST_LOG_NOTICE, "%s\n", string);
02832 }
02833
02834
02835 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02836 {
02837 struct ast_vm_user *vmu;
02838
02839 ast_debug(4, "Entering callback mm_login\n");
02840
02841 ast_copy_string(user, mb->user, MAILTMPLEN);
02842
02843
02844 if (!ast_strlen_zero(authpassword)) {
02845 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02846 } else {
02847 AST_LIST_TRAVERSE(&users, vmu, list) {
02848 if (!strcasecmp(mb->user, vmu->imapuser)) {
02849 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02850 break;
02851 }
02852 }
02853 if (!vmu) {
02854 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02855 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02856 free_user(vmu);
02857 }
02858 }
02859 }
02860 }
02861
02862
02863 void mm_critical(MAILSTREAM * stream)
02864 {
02865 }
02866
02867
02868 void mm_nocritical(MAILSTREAM * stream)
02869 {
02870 }
02871
02872
02873 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02874 {
02875 kill (getpid (), SIGSTOP);
02876 return NIL;
02877 }
02878
02879
02880 void mm_fatal(char *string)
02881 {
02882 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02883 }
02884
02885
02886 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02887 {
02888 struct vm_state *vms;
02889 char *mailbox = stream->mailbox, *user;
02890 char buf[1024] = "";
02891 unsigned long usage = 0, limit = 0;
02892
02893 while (pquota) {
02894 usage = pquota->usage;
02895 limit = pquota->limit;
02896 pquota = pquota->next;
02897 }
02898
02899 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)))) {
02900 ast_log(AST_LOG_ERROR, "No state found.\n");
02901 return;
02902 }
02903
02904 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02905
02906 vms->quota_usage = usage;
02907 vms->quota_limit = limit;
02908 }
02909
02910 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02911 {
02912 char *start, *eol_pnt;
02913 int taglen;
02914
02915 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02916 return NULL;
02917
02918 taglen = strlen(tag) + 1;
02919 if (taglen < 1)
02920 return NULL;
02921
02922 if (!(start = strstr(header, tag)))
02923 return NULL;
02924
02925
02926 memset(buf, 0, len);
02927
02928 ast_copy_string(buf, start+taglen, len);
02929 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02930 *eol_pnt = '\0';
02931 return buf;
02932 }
02933
02934 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02935 {
02936 char *start, *quote, *eol_pnt;
02937
02938 if (ast_strlen_zero(mailbox))
02939 return NULL;
02940
02941 if (!(start = strstr(mailbox, "/user=")))
02942 return NULL;
02943
02944 ast_copy_string(buf, start+6, len);
02945
02946 if (!(quote = strchr(buf, '\"'))) {
02947 if (!(eol_pnt = strchr(buf, '/')))
02948 eol_pnt = strchr(buf,'}');
02949 *eol_pnt = '\0';
02950 return buf;
02951 } else {
02952 eol_pnt = strchr(buf+1,'\"');
02953 *eol_pnt = '\0';
02954 return buf+1;
02955 }
02956 }
02957
02958 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02959 {
02960 struct vm_state *vms_p;
02961
02962 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02963 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02964 return vms_p;
02965 }
02966 if (option_debug > 4)
02967 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02968 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02969 return NULL;
02970 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02971 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
02972 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02973 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02974 vms_p->mailstream = NIL;
02975 vms_p->imapversion = vmu->imapversion;
02976 if (option_debug > 4)
02977 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
02978 vms_p->updated = 1;
02979
02980 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
02981 init_vm_state(vms_p);
02982 vmstate_insert(vms_p);
02983 return vms_p;
02984 }
02985
02986 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
02987 {
02988 struct vmstate *vlist = NULL;
02989
02990 if (interactive) {
02991 struct vm_state *vms;
02992 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02993 vms = pthread_getspecific(ts_vmstate.key);
02994 return vms;
02995 }
02996
02997 AST_LIST_LOCK(&vmstates);
02998 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02999 if (!vlist->vms) {
03000 ast_debug(3, "error: vms is NULL for %s\n", user);
03001 continue;
03002 }
03003 if (vlist->vms->imapversion != imapversion) {
03004 continue;
03005 }
03006 if (!vlist->vms->imapuser) {
03007 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03008 continue;
03009 }
03010
03011 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03012 AST_LIST_UNLOCK(&vmstates);
03013 return vlist->vms;
03014 }
03015 }
03016 AST_LIST_UNLOCK(&vmstates);
03017
03018 ast_debug(3, "%s not found in vmstates\n", user);
03019
03020 return NULL;
03021 }
03022
03023 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03024 {
03025
03026 struct vmstate *vlist = NULL;
03027 const char *local_context = S_OR(context, "default");
03028
03029 if (interactive) {
03030 struct vm_state *vms;
03031 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03032 vms = pthread_getspecific(ts_vmstate.key);
03033 return vms;
03034 }
03035
03036 AST_LIST_LOCK(&vmstates);
03037 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03038 if (!vlist->vms) {
03039 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03040 continue;
03041 }
03042 if (vlist->vms->imapversion != imapversion) {
03043 continue;
03044 }
03045 if (!vlist->vms->username || !vlist->vms->context) {
03046 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03047 continue;
03048 }
03049
03050 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);
03051
03052 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03053 ast_debug(3, "Found it!\n");
03054 AST_LIST_UNLOCK(&vmstates);
03055 return vlist->vms;
03056 }
03057 }
03058 AST_LIST_UNLOCK(&vmstates);
03059
03060 ast_debug(3, "%s not found in vmstates\n", mailbox);
03061
03062 return NULL;
03063 }
03064
03065 static void vmstate_insert(struct vm_state *vms)
03066 {
03067 struct vmstate *v;
03068 struct vm_state *altvms;
03069
03070
03071
03072
03073 if (vms->interactive == 1) {
03074 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03075 if (altvms) {
03076 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03077 vms->newmessages = altvms->newmessages;
03078 vms->oldmessages = altvms->oldmessages;
03079 vms->vmArrayIndex = altvms->vmArrayIndex;
03080 vms->lastmsg = altvms->lastmsg;
03081 vms->curmsg = altvms->curmsg;
03082
03083 vms->persist_vms = altvms;
03084
03085 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03086 vms->mailstream = altvms->mailstream;
03087 #else
03088 vms->mailstream = NIL;
03089 #endif
03090 }
03091 return;
03092 }
03093
03094 if (!(v = ast_calloc(1, sizeof(*v))))
03095 return;
03096
03097 v->vms = vms;
03098
03099 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03100
03101 AST_LIST_LOCK(&vmstates);
03102 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03103 AST_LIST_UNLOCK(&vmstates);
03104 }
03105
03106 static void vmstate_delete(struct vm_state *vms)
03107 {
03108 struct vmstate *vc = NULL;
03109 struct vm_state *altvms = NULL;
03110
03111
03112
03113 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03114 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03115 altvms->newmessages = vms->newmessages;
03116 altvms->oldmessages = vms->oldmessages;
03117 altvms->updated = 1;
03118 vms->mailstream = mail_close(vms->mailstream);
03119
03120
03121 return;
03122 }
03123
03124 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03125
03126 AST_LIST_LOCK(&vmstates);
03127 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03128 if (vc->vms == vms) {
03129 AST_LIST_REMOVE_CURRENT(list);
03130 break;
03131 }
03132 }
03133 AST_LIST_TRAVERSE_SAFE_END
03134 AST_LIST_UNLOCK(&vmstates);
03135
03136 if (vc) {
03137 ast_mutex_destroy(&vc->vms->lock);
03138 ast_free(vc);
03139 }
03140 else
03141 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03142 }
03143
03144 static void set_update(MAILSTREAM * stream)
03145 {
03146 struct vm_state *vms;
03147 char *mailbox = stream->mailbox, *user;
03148 char buf[1024] = "";
03149
03150 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03151 if (user && option_debug > 2)
03152 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03153 return;
03154 }
03155
03156 ast_debug(3, "User %s mailbox set for update.\n", user);
03157
03158 vms->updated = 1;
03159 }
03160
03161 static void init_vm_state(struct vm_state *vms)
03162 {
03163 int x;
03164 vms->vmArrayIndex = 0;
03165 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03166 vms->msgArray[x] = 0;
03167 }
03168 ast_mutex_init(&vms->lock);
03169 }
03170
03171 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03172 {
03173 char *body_content;
03174 char *body_decoded;
03175 char *fn = is_intro ? vms->introfn : vms->fn;
03176 unsigned long len;
03177 unsigned long newlen;
03178 char filename[256];
03179
03180 if (!body || body == NIL)
03181 return -1;
03182
03183 ast_mutex_lock(&vms->lock);
03184 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03185 ast_mutex_unlock(&vms->lock);
03186 if (body_content != NIL) {
03187 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03188
03189 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03190
03191 if (!newlen) {
03192 return -1;
03193 }
03194 write_file(filename, (char *) body_decoded, newlen);
03195 } else {
03196 ast_debug(5, "Body of message is NULL.\n");
03197 return -1;
03198 }
03199 return 0;
03200 }
03201
03202
03203
03204
03205
03206
03207
03208
03209 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03210 char tmp[50];
03211 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03212 mail_list(stream, tmp, "*");
03213 }
03214
03215
03216
03217
03218
03219
03220
03221
03222 static void check_quota(struct vm_state *vms, char *mailbox) {
03223 ast_mutex_lock(&vms->lock);
03224 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03225 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03226 if (vms && vms->mailstream != NULL) {
03227 imap_getquotaroot(vms->mailstream, mailbox);
03228 } else {
03229 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03230 }
03231 ast_mutex_unlock(&vms->lock);
03232 }
03233
03234 #endif
03235
03236
03237
03238
03239
03240 static int vm_lock_path(const char *path)
03241 {
03242 switch (ast_lock_path(path)) {
03243 case AST_LOCK_TIMEOUT:
03244 return -1;
03245 default:
03246 return 0;
03247 }
03248 }
03249
03250
03251 #ifdef ODBC_STORAGE
03252 struct generic_prepare_struct {
03253 char *sql;
03254 int argc;
03255 char **argv;
03256 };
03257
03258 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03259 {
03260 struct generic_prepare_struct *gps = data;
03261 int res, i;
03262 SQLHSTMT stmt;
03263
03264 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03265 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03266 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03267 return NULL;
03268 }
03269 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03270 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03271 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03272 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03273 return NULL;
03274 }
03275 for (i = 0; i < gps->argc; i++)
03276 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03277
03278 return stmt;
03279 }
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294
03295 static int retrieve_file(char *dir, int msgnum)
03296 {
03297 int x = 0;
03298 int res;
03299 int fd = -1;
03300 size_t fdlen = 0;
03301 void *fdm = MAP_FAILED;
03302 SQLSMALLINT colcount = 0;
03303 SQLHSTMT stmt;
03304 char sql[PATH_MAX];
03305 char fmt[80]="";
03306 char *c;
03307 char coltitle[256];
03308 SQLSMALLINT collen;
03309 SQLSMALLINT datatype;
03310 SQLSMALLINT decimaldigits;
03311 SQLSMALLINT nullable;
03312 SQLULEN colsize;
03313 SQLLEN colsize2;
03314 FILE *f = NULL;
03315 char rowdata[80];
03316 char fn[PATH_MAX];
03317 char full_fn[PATH_MAX];
03318 char msgnums[80];
03319 char *argv[] = { dir, msgnums };
03320 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03321
03322 struct odbc_obj *obj;
03323 obj = ast_odbc_request_obj(odbc_database, 0);
03324 if (obj) {
03325 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03326 c = strchr(fmt, '|');
03327 if (c)
03328 *c = '\0';
03329 if (!strcasecmp(fmt, "wav49"))
03330 strcpy(fmt, "WAV");
03331 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03332 if (msgnum > -1)
03333 make_file(fn, sizeof(fn), dir, msgnum);
03334 else
03335 ast_copy_string(fn, dir, sizeof(fn));
03336
03337
03338 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03339
03340 if (!(f = fopen(full_fn, "w+"))) {
03341 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03342 goto yuck;
03343 }
03344
03345 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03346 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03347 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03348 if (!stmt) {
03349 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03350 ast_odbc_release_obj(obj);
03351 goto yuck;
03352 }
03353 res = SQLFetch(stmt);
03354 if (res == SQL_NO_DATA) {
03355 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03356 ast_odbc_release_obj(obj);
03357 goto yuck;
03358 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03359 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03360 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03361 ast_odbc_release_obj(obj);
03362 goto yuck;
03363 }
03364 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03365 if (fd < 0) {
03366 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03367 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03368 ast_odbc_release_obj(obj);
03369 goto yuck;
03370 }
03371 res = SQLNumResultCols(stmt, &colcount);
03372 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03373 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03374 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03375 ast_odbc_release_obj(obj);
03376 goto yuck;
03377 }
03378 if (f)
03379 fprintf(f, "[message]\n");
03380 for (x = 0; x < colcount; x++) {
03381 rowdata[0] = '\0';
03382 colsize = 0;
03383 collen = sizeof(coltitle);
03384 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03385 &datatype, &colsize, &decimaldigits, &nullable);
03386 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03387 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03388 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03389 ast_odbc_release_obj(obj);
03390 goto yuck;
03391 }
03392 if (!strcasecmp(coltitle, "recording")) {
03393 off_t offset;
03394 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03395 fdlen = colsize2;
03396 if (fd > -1) {
03397 char tmp[1]="";
03398 lseek(fd, fdlen - 1, SEEK_SET);
03399 if (write(fd, tmp, 1) != 1) {
03400 close(fd);
03401 fd = -1;
03402 continue;
03403 }
03404
03405 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03406 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03407 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03408 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03409 ast_odbc_release_obj(obj);
03410 goto yuck;
03411 } else {
03412 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03413 munmap(fdm, CHUNKSIZE);
03414 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03415 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03416 unlink(full_fn);
03417 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03418 ast_odbc_release_obj(obj);
03419 goto yuck;
03420 }
03421 }
03422 }
03423 if (truncate(full_fn, fdlen) < 0) {
03424 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03425 }
03426 }
03427 } else {
03428 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03429 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03430 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03431 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03432 ast_odbc_release_obj(obj);
03433 goto yuck;
03434 }
03435 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03436 fprintf(f, "%s=%s\n", coltitle, rowdata);
03437 }
03438 }
03439 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03440 ast_odbc_release_obj(obj);
03441 } else
03442 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03443 yuck:
03444 if (f)
03445 fclose(f);
03446 if (fd > -1)
03447 close(fd);
03448 return x - 1;
03449 }
03450
03451
03452
03453
03454
03455
03456
03457
03458
03459
03460
03461
03462 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03463 {
03464 int x = 0;
03465 int res;
03466 SQLHSTMT stmt;
03467 char sql[PATH_MAX];
03468 char rowdata[20];
03469 char *argv[] = { dir };
03470 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03471
03472 struct odbc_obj *obj;
03473 obj = ast_odbc_request_obj(odbc_database, 0);
03474 if (obj) {
03475 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03476
03477 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03478 if (!stmt) {
03479 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03480 ast_odbc_release_obj(obj);
03481 goto yuck;
03482 }
03483 res = SQLFetch(stmt);
03484 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03485 if (res == SQL_NO_DATA) {
03486 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03487 } else {
03488 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03489 }
03490
03491 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03492 ast_odbc_release_obj(obj);
03493 goto yuck;
03494 }
03495 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03496 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03497 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03498 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03499 ast_odbc_release_obj(obj);
03500 goto yuck;
03501 }
03502 if (sscanf(rowdata, "%30d", &x) != 1)
03503 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03504 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03505 ast_odbc_release_obj(obj);
03506 return x;
03507 } else
03508 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03509 yuck:
03510 return x - 1;
03511 }
03512
03513
03514
03515
03516
03517
03518
03519
03520
03521
03522 static int message_exists(char *dir, int msgnum)
03523 {
03524 int x = 0;
03525 int res;
03526 SQLHSTMT stmt;
03527 char sql[PATH_MAX];
03528 char rowdata[20];
03529 char msgnums[20];
03530 char *argv[] = { dir, msgnums };
03531 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03532
03533 struct odbc_obj *obj;
03534 obj = ast_odbc_request_obj(odbc_database, 0);
03535 if (obj) {
03536 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03537 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03538 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03539 if (!stmt) {
03540 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03541 ast_odbc_release_obj(obj);
03542 goto yuck;
03543 }
03544 res = SQLFetch(stmt);
03545 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03546 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03547 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03548 ast_odbc_release_obj(obj);
03549 goto yuck;
03550 }
03551 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03552 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03553 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03554 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03555 ast_odbc_release_obj(obj);
03556 goto yuck;
03557 }
03558 if (sscanf(rowdata, "%30d", &x) != 1)
03559 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03560 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03561 ast_odbc_release_obj(obj);
03562 } else
03563 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03564 yuck:
03565 return x;
03566 }
03567
03568
03569
03570
03571
03572
03573
03574
03575
03576
03577 static int count_messages(struct ast_vm_user *vmu, char *dir)
03578 {
03579 int x = 0;
03580 int res;
03581 SQLHSTMT stmt;
03582 char sql[PATH_MAX];
03583 char rowdata[20];
03584 char *argv[] = { dir };
03585 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03586
03587 struct odbc_obj *obj;
03588 obj = ast_odbc_request_obj(odbc_database, 0);
03589 if (obj) {
03590 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03591 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03592 if (!stmt) {
03593 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03594 ast_odbc_release_obj(obj);
03595 goto yuck;
03596 }
03597 res = SQLFetch(stmt);
03598 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03599 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03600 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03601 ast_odbc_release_obj(obj);
03602 goto yuck;
03603 }
03604 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03605 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03606 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03607 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03608 ast_odbc_release_obj(obj);
03609 goto yuck;
03610 }
03611 if (sscanf(rowdata, "%30d", &x) != 1)
03612 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03613 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03614 ast_odbc_release_obj(obj);
03615 return x;
03616 } else
03617 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03618 yuck:
03619 return x - 1;
03620
03621 }
03622
03623
03624
03625
03626
03627
03628
03629
03630
03631
03632
03633 static void delete_file(const char *sdir, int smsg)
03634 {
03635 SQLHSTMT stmt;
03636 char sql[PATH_MAX];
03637 char msgnums[20];
03638 char *argv[] = { NULL, msgnums };
03639 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03640 struct odbc_obj *obj;
03641
03642 argv[0] = ast_strdupa(sdir);
03643
03644 obj = ast_odbc_request_obj(odbc_database, 0);
03645 if (obj) {
03646 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03647 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03648 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03649 if (!stmt)
03650 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03651 else
03652 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03653 ast_odbc_release_obj(obj);
03654 } else
03655 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03656 return;
03657 }
03658
03659
03660
03661
03662
03663
03664
03665
03666
03667
03668
03669
03670 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03671 {
03672 SQLHSTMT stmt;
03673 char sql[512];
03674 char msgnums[20];
03675 char msgnumd[20];
03676 struct odbc_obj *obj;
03677 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03678 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03679
03680 delete_file(ddir, dmsg);
03681 obj = ast_odbc_request_obj(odbc_database, 0);
03682 if (obj) {
03683 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03684 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03685 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);
03686 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03687 if (!stmt)
03688 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03689 else
03690 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03691 ast_odbc_release_obj(obj);
03692 } else
03693 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03694 return;
03695 }
03696
03697 struct insert_data {
03698 char *sql;
03699 const char *dir;
03700 const char *msgnums;
03701 void *data;
03702 SQLLEN datalen;
03703 SQLLEN indlen;
03704 const char *context;
03705 const char *macrocontext;
03706 const char *callerid;
03707 const char *origtime;
03708 const char *duration;
03709 const char *mailboxuser;
03710 const char *mailboxcontext;
03711 const char *category;
03712 const char *flag;
03713 };
03714
03715 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03716 {
03717 struct insert_data *data = vdata;
03718 int res;
03719 SQLHSTMT stmt;
03720
03721 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03722 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03723 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03724 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03725 return NULL;
03726 }
03727
03728 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03729 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03730 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03731 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03732 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03733 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03734 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03735 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03736 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03737 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03738 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03739 if (!ast_strlen_zero(data->category)) {
03740 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03741 }
03742 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03743 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03744 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03745 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03746 return NULL;
03747 }
03748
03749 return stmt;
03750 }
03751
03752
03753
03754
03755
03756
03757
03758
03759
03760
03761
03762
03763
03764
03765 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03766 {
03767 int res = 0;
03768 int fd = -1;
03769 void *fdm = MAP_FAILED;
03770 off_t fdlen = -1;
03771 SQLHSTMT stmt;
03772 char sql[PATH_MAX];
03773 char msgnums[20];
03774 char fn[PATH_MAX];
03775 char full_fn[PATH_MAX];
03776 char fmt[80]="";
03777 char *c;
03778 struct ast_config *cfg = NULL;
03779 struct odbc_obj *obj;
03780 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03781 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03782 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03783
03784 delete_file(dir, msgnum);
03785 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03786 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03787 return -1;
03788 }
03789
03790 do {
03791 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03792 c = strchr(fmt, '|');
03793 if (c)
03794 *c = '\0';
03795 if (!strcasecmp(fmt, "wav49"))
03796 strcpy(fmt, "WAV");
03797 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03798 if (msgnum > -1)
03799 make_file(fn, sizeof(fn), dir, msgnum);
03800 else
03801 ast_copy_string(fn, dir, sizeof(fn));
03802 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03803 cfg = ast_config_load(full_fn, config_flags);
03804 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03805 fd = open(full_fn, O_RDWR);
03806 if (fd < 0) {
03807 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03808 res = -1;
03809 break;
03810 }
03811 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03812 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03813 idata.context = "";
03814 }
03815 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03816 idata.macrocontext = "";
03817 }
03818 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03819 idata.callerid = "";
03820 }
03821 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03822 idata.origtime = "";
03823 }
03824 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03825 idata.duration = "";
03826 }
03827 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03828 idata.category = "";
03829 }
03830 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03831 idata.flag = "";
03832 }
03833 }
03834 fdlen = lseek(fd, 0, SEEK_END);
03835 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03836 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03837 res = -1;
03838 break;
03839 }
03840 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03841 if (fdm == MAP_FAILED) {
03842 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03843 res = -1;
03844 break;
03845 }
03846 idata.data = fdm;
03847 idata.datalen = idata.indlen = fdlen;
03848
03849 if (!ast_strlen_zero(idata.category))
03850 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03851 else
03852 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03853
03854 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03855 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03856 } else {
03857 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03858 res = -1;
03859 }
03860 } while (0);
03861 if (obj) {
03862 ast_odbc_release_obj(obj);
03863 }
03864 if (cfg)
03865 ast_config_destroy(cfg);
03866 if (fdm != MAP_FAILED)
03867 munmap(fdm, fdlen);
03868 if (fd > -1)
03869 close(fd);
03870 return res;
03871 }
03872
03873
03874
03875
03876
03877
03878
03879
03880
03881
03882
03883
03884
03885
03886 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03887 {
03888 SQLHSTMT stmt;
03889 char sql[PATH_MAX];
03890 char msgnums[20];
03891 char msgnumd[20];
03892 struct odbc_obj *obj;
03893 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03894 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03895
03896 delete_file(ddir, dmsg);
03897 obj = ast_odbc_request_obj(odbc_database, 0);
03898 if (obj) {
03899 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03900 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03901 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03902 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03903 if (!stmt)
03904 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03905 else
03906 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03907 ast_odbc_release_obj(obj);
03908 } else
03909 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03910 return;
03911 }
03912
03913
03914
03915
03916
03917
03918
03919
03920
03921
03922
03923
03924 static int remove_file(char *dir, int msgnum)
03925 {
03926 char fn[PATH_MAX];
03927 char full_fn[PATH_MAX];
03928 char msgnums[80];
03929
03930 if (msgnum > -1) {
03931 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03932 make_file(fn, sizeof(fn), dir, msgnum);
03933 } else
03934 ast_copy_string(fn, dir, sizeof(fn));
03935 ast_filedelete(fn, NULL);
03936 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03937 unlink(full_fn);
03938 return 0;
03939 }
03940 #else
03941 #ifndef IMAP_STORAGE
03942
03943
03944
03945
03946
03947
03948
03949
03950
03951 static int count_messages(struct ast_vm_user *vmu, char *dir)
03952 {
03953
03954 int vmcount = 0;
03955 DIR *vmdir = NULL;
03956 struct dirent *vment = NULL;
03957
03958 if (vm_lock_path(dir))
03959 return ERROR_LOCK_PATH;
03960
03961 if ((vmdir = opendir(dir))) {
03962 while ((vment = readdir(vmdir))) {
03963 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03964 vmcount++;
03965 }
03966 }
03967 closedir(vmdir);
03968 }
03969 ast_unlock_path(dir);
03970
03971 return vmcount;
03972 }
03973
03974
03975
03976
03977
03978
03979
03980
03981 static void rename_file(char *sfn, char *dfn)
03982 {
03983 char stxt[PATH_MAX];
03984 char dtxt[PATH_MAX];
03985 ast_filerename(sfn, dfn, NULL);
03986 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
03987 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
03988 if (ast_check_realtime("voicemail_data")) {
03989 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
03990 }
03991 rename(stxt, dtxt);
03992 }
03993
03994
03995
03996
03997
03998
03999
04000
04001
04002
04003
04004
04005 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04006 {
04007 int x;
04008 unsigned char map[MAXMSGLIMIT] = "";
04009 DIR *msgdir;
04010 struct dirent *msgdirent;
04011 int msgdirint;
04012 char extension[4];
04013 int stopcount = 0;
04014
04015
04016
04017
04018
04019 if (!(msgdir = opendir(dir))) {
04020 return -1;
04021 }
04022
04023 while ((msgdirent = readdir(msgdir))) {
04024 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04025 map[msgdirint] = 1;
04026 stopcount++;
04027 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04028 }
04029 }
04030 closedir(msgdir);
04031
04032 for (x = 0; x < vmu->maxmsg; x++) {
04033 if (map[x] == 1) {
04034 stopcount--;
04035 } else if (map[x] == 0 && !stopcount) {
04036 break;
04037 }
04038 }
04039
04040 return x - 1;
04041 }
04042
04043 #endif
04044 #endif
04045 #ifndef IMAP_STORAGE
04046
04047
04048
04049
04050
04051
04052
04053
04054
04055
04056 static int copy(char *infile, char *outfile)
04057 {
04058 int ifd;
04059 int ofd;
04060 int res;
04061 int len;
04062 char buf[4096];
04063
04064 #ifdef HARDLINK_WHEN_POSSIBLE
04065
04066 if (link(infile, outfile)) {
04067 #endif
04068 if ((ifd = open(infile, O_RDONLY)) < 0) {
04069 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04070 return -1;
04071 }
04072 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04073 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04074 close(ifd);
04075 return -1;
04076 }
04077 do {
04078 len = read(ifd, buf, sizeof(buf));
04079 if (len < 0) {
04080 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04081 close(ifd);
04082 close(ofd);
04083 unlink(outfile);
04084 } else if (len) {
04085 res = write(ofd, buf, len);
04086 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04087 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04088 close(ifd);
04089 close(ofd);
04090 unlink(outfile);
04091 }
04092 }
04093 } while (len);
04094 close(ifd);
04095 close(ofd);
04096 return 0;
04097 #ifdef HARDLINK_WHEN_POSSIBLE
04098 } else {
04099
04100 return 0;
04101 }
04102 #endif
04103 }
04104
04105
04106
04107
04108
04109
04110
04111
04112
04113
04114 static void copy_plain_file(char *frompath, char *topath)
04115 {
04116 char frompath2[PATH_MAX], topath2[PATH_MAX];
04117 struct ast_variable *tmp,*var = NULL;
04118 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04119 ast_filecopy(frompath, topath, NULL);
04120 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04121 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04122 if (ast_check_realtime("voicemail_data")) {
04123 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04124
04125 for (tmp = var; tmp; tmp = tmp->next) {
04126 if (!strcasecmp(tmp->name, "origmailbox")) {
04127 origmailbox = tmp->value;
04128 } else if (!strcasecmp(tmp->name, "context")) {
04129 context = tmp->value;
04130 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04131 macrocontext = tmp->value;
04132 } else if (!strcasecmp(tmp->name, "exten")) {
04133 exten = tmp->value;
04134 } else if (!strcasecmp(tmp->name, "priority")) {
04135 priority = tmp->value;
04136 } else if (!strcasecmp(tmp->name, "callerchan")) {
04137 callerchan = tmp->value;
04138 } else if (!strcasecmp(tmp->name, "callerid")) {
04139 callerid = tmp->value;
04140 } else if (!strcasecmp(tmp->name, "origdate")) {
04141 origdate = tmp->value;
04142 } else if (!strcasecmp(tmp->name, "origtime")) {
04143 origtime = tmp->value;
04144 } else if (!strcasecmp(tmp->name, "category")) {
04145 category = tmp->value;
04146 } else if (!strcasecmp(tmp->name, "duration")) {
04147 duration = tmp->value;
04148 }
04149 }
04150 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);
04151 }
04152 copy(frompath2, topath2);
04153 ast_variables_destroy(var);
04154 }
04155 #endif
04156
04157
04158
04159
04160
04161
04162
04163
04164
04165 static int vm_delete(char *file)
04166 {
04167 char *txt;
04168 int txtsize = 0;
04169
04170 txtsize = (strlen(file) + 5)*sizeof(char);
04171 txt = alloca(txtsize);
04172
04173
04174
04175 if (ast_check_realtime("voicemail_data")) {
04176 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04177 }
04178 snprintf(txt, txtsize, "%s.txt", file);
04179 unlink(txt);
04180 return ast_filedelete(file, NULL);
04181 }
04182
04183
04184
04185
04186 static int inbuf(struct baseio *bio, FILE *fi)
04187 {
04188 int l;
04189
04190 if (bio->ateof)
04191 return 0;
04192
04193 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04194 if (ferror(fi))
04195 return -1;
04196
04197 bio->ateof = 1;
04198 return 0;
04199 }
04200
04201 bio->iolen = l;
04202 bio->iocp = 0;
04203
04204 return 1;
04205 }
04206
04207
04208
04209
04210 static int inchar(struct baseio *bio, FILE *fi)
04211 {
04212 if (bio->iocp>=bio->iolen) {
04213 if (!inbuf(bio, fi))
04214 return EOF;
04215 }
04216
04217 return bio->iobuf[bio->iocp++];
04218 }
04219
04220
04221
04222
04223 static int ochar(struct baseio *bio, int c, FILE *so)
04224 {
04225 if (bio->linelength >= BASELINELEN) {
04226 if (fputs(ENDL, so) == EOF) {
04227 return -1;
04228 }
04229
04230 bio->linelength = 0;
04231 }
04232
04233 if (putc(((unsigned char) c), so) == EOF) {
04234 return -1;
04235 }
04236
04237 bio->linelength++;
04238
04239 return 1;
04240 }
04241
04242
04243
04244
04245
04246
04247
04248
04249
04250
04251 static int base_encode(char *filename, FILE *so)
04252 {
04253 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04254 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04255 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04256 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04257 int i, hiteof = 0;
04258 FILE *fi;
04259 struct baseio bio;
04260
04261 memset(&bio, 0, sizeof(bio));
04262 bio.iocp = BASEMAXINLINE;
04263
04264 if (!(fi = fopen(filename, "rb"))) {
04265 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04266 return -1;
04267 }
04268
04269 while (!hiteof){
04270 unsigned char igroup[3], ogroup[4];
04271 int c, n;
04272
04273 memset(igroup, 0, sizeof(igroup));
04274
04275 for (n = 0; n < 3; n++) {
04276 if ((c = inchar(&bio, fi)) == EOF) {
04277 hiteof = 1;
04278 break;
04279 }
04280
04281 igroup[n] = (unsigned char) c;
04282 }
04283
04284 if (n > 0) {
04285 ogroup[0]= dtable[igroup[0] >> 2];
04286 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04287 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04288 ogroup[3]= dtable[igroup[2] & 0x3F];
04289
04290 if (n < 3) {
04291 ogroup[3] = '=';
04292
04293 if (n < 2)
04294 ogroup[2] = '=';
04295 }
04296
04297 for (i = 0; i < 4; i++)
04298 ochar(&bio, ogroup[i], so);
04299 }
04300 }
04301
04302 fclose(fi);
04303
04304 if (fputs(ENDL, so) == EOF) {
04305 return 0;
04306 }
04307
04308 return 1;
04309 }
04310
04311 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, const char *category, const char *flag)
04312 {
04313 char callerid[256];
04314 char num[12];
04315 char fromdir[256], fromfile[256];
04316 struct ast_config *msg_cfg;
04317 const char *origcallerid, *origtime;
04318 char origcidname[80], origcidnum[80], origdate[80];
04319 int inttime;
04320 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04321
04322
04323 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04324 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04325 snprintf(num, sizeof(num), "%d", msgnum);
04326 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04327 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04328 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04329 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04330 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04331 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04332 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04333 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04334 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04335 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04336
04337
04338 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04339 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04340 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04341 strcat(fromfile, ".txt");
04342 }
04343 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04344 if (option_debug > 0) {
04345 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04346 }
04347 return;
04348 }
04349
04350 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04351 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04352 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04353 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04354 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04355 }
04356
04357 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04358 struct timeval tv = { inttime, };
04359 struct ast_tm tm;
04360 ast_localtime(&tv, &tm, NULL);
04361 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04362 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04363 }
04364 ast_config_destroy(msg_cfg);
04365 }
04366
04367
04368
04369
04370
04371
04372
04373
04374
04375 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04376 {
04377 const char *ptr;
04378
04379
04380 ast_str_set(buf, maxlen, "\"");
04381 for (ptr = from; *ptr; ptr++) {
04382 if (*ptr == '"' || *ptr == '\\') {
04383 ast_str_append(buf, maxlen, "\\%c", *ptr);
04384 } else {
04385 ast_str_append(buf, maxlen, "%c", *ptr);
04386 }
04387 }
04388 ast_str_append(buf, maxlen, "\"");
04389
04390 return ast_str_buffer(*buf);
04391 }
04392
04393
04394
04395
04396
04397 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04398 {
04399 const struct vm_zone *z = NULL;
04400 struct timeval t = ast_tvnow();
04401
04402
04403 if (!ast_strlen_zero(vmu->zonetag)) {
04404
04405 AST_LIST_LOCK(&zones);
04406 AST_LIST_TRAVERSE(&zones, z, list) {
04407 if (!strcmp(z->name, vmu->zonetag))
04408 break;
04409 }
04410 AST_LIST_UNLOCK(&zones);
04411 }
04412 ast_localtime(&t, tm, z ? z->timezone : NULL);
04413 return tm;
04414 }
04415
04416
04417
04418
04419
04420 static int check_mime(const char *str)
04421 {
04422 for (; *str; str++) {
04423 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04424 return 1;
04425 }
04426 }
04427 return 0;
04428 }
04429
04430
04431
04432
04433
04434
04435
04436
04437
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04448 {
04449 struct ast_str *tmp = ast_str_alloca(80);
04450 int first_section = 1;
04451
04452 ast_str_reset(*end);
04453 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04454 for (; *start; start++) {
04455 int need_encoding = 0;
04456 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04457 need_encoding = 1;
04458 }
04459 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04460 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04461 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04462 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04463
04464 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04465 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04466 first_section = 0;
04467 }
04468 if (need_encoding && *start == ' ') {
04469 ast_str_append(&tmp, -1, "_");
04470 } else if (need_encoding) {
04471 ast_str_append(&tmp, -1, "=%hhX", *start);
04472 } else {
04473 ast_str_append(&tmp, -1, "%c", *start);
04474 }
04475 }
04476 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04477 return ast_str_buffer(*end);
04478 }
04479
04480
04481
04482
04483
04484
04485
04486
04487
04488
04489
04490
04491
04492
04493
04494
04495
04496
04497
04498
04499
04500
04501
04502
04503 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)
04504 {
04505 char date[256];
04506 char host[MAXHOSTNAMELEN] = "";
04507 char who[256];
04508 char bound[256];
04509 char dur[256];
04510 struct ast_tm tm;
04511 char enc_cidnum[256] = "", enc_cidname[256] = "";
04512 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04513 char *greeting_attachment;
04514 char filename[256];
04515
04516 if (!str1 || !str2) {
04517 ast_free(str1);
04518 ast_free(str2);
04519 return;
04520 }
04521
04522 if (cidnum) {
04523 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04524 }
04525 if (cidname) {
04526 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04527 }
04528 gethostname(host, sizeof(host) - 1);
04529
04530 if (strchr(srcemail, '@')) {
04531 ast_copy_string(who, srcemail, sizeof(who));
04532 } else {
04533 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04534 }
04535
04536 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04537 if (greeting_attachment) {
04538 *greeting_attachment++ = '\0';
04539 }
04540
04541 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04542 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04543 fprintf(p, "Date: %s" ENDL, date);
04544
04545
04546 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04547
04548 if (!ast_strlen_zero(fromstring)) {
04549 struct ast_channel *ast;
04550 if ((ast = ast_dummy_channel_alloc())) {
04551 char *ptr;
04552 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04553 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04554
04555 if (check_mime(ast_str_buffer(str1))) {
04556 int first_line = 1;
04557 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04558 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04559 *ptr = '\0';
04560 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04561 first_line = 0;
04562
04563 ast_str_set(&str2, 0, "%s", ptr + 1);
04564 }
04565 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04566 } else {
04567 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04568 }
04569 ast = ast_channel_unref(ast);
04570 } else {
04571 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04572 }
04573 } else {
04574 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04575 }
04576
04577 if (check_mime(vmu->fullname)) {
04578 int first_line = 1;
04579 char *ptr;
04580 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04581 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04582 *ptr = '\0';
04583 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04584 first_line = 0;
04585
04586 ast_str_set(&str2, 0, "%s", ptr + 1);
04587 }
04588 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04589 } else {
04590 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04591 }
04592
04593 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04594 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04595 struct ast_channel *ast;
04596 if ((ast = ast_dummy_channel_alloc())) {
04597 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04598 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04599 if (check_mime(ast_str_buffer(str1))) {
04600 int first_line = 1;
04601 char *ptr;
04602 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04603 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04604 *ptr = '\0';
04605 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04606 first_line = 0;
04607
04608 ast_str_set(&str2, 0, "%s", ptr + 1);
04609 }
04610 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04611 } else {
04612 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04613 }
04614 ast = ast_channel_unref(ast);
04615 } else {
04616 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04617 }
04618 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04619 if (ast_strlen_zero(flag)) {
04620 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04621 } else {
04622 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04623 }
04624 } else {
04625 if (ast_strlen_zero(flag)) {
04626 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04627 } else {
04628 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04629 }
04630 }
04631
04632 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04633 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04634 if (imap) {
04635
04636 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04637
04638 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04639 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04640 #ifdef IMAP_STORAGE
04641 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04642 #else
04643 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04644 #endif
04645
04646 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04647 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04648 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04649 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04650 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04651 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04652 if (!ast_strlen_zero(category)) {
04653 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04654 } else {
04655 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04656 }
04657 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04658 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04659 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04660 }
04661 if (!ast_strlen_zero(cidnum)) {
04662 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04663 }
04664 if (!ast_strlen_zero(cidname)) {
04665 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04666 }
04667 fprintf(p, "MIME-Version: 1.0" ENDL);
04668 if (attach_user_voicemail) {
04669
04670 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04671 (int) getpid(), (unsigned int) ast_random());
04672
04673 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04674 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04675 fprintf(p, "--%s" ENDL, bound);
04676 }
04677 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04678 if (emailbody || vmu->emailbody) {
04679 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04680 struct ast_channel *ast;
04681 if ((ast = ast_dummy_channel_alloc())) {
04682 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04683 ast_str_substitute_variables(&str1, 0, ast, e_body);
04684 #ifdef IMAP_STORAGE
04685 {
04686
04687 char *line = ast_str_buffer(str1), *next;
04688 do {
04689
04690 if ((next = strchr(line, '\n'))) {
04691 *next++ = '\0';
04692 }
04693 fprintf(p, "%s" ENDL, line);
04694 line = next;
04695 } while (!ast_strlen_zero(line));
04696 }
04697 #else
04698 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04699 #endif
04700 ast = ast_channel_unref(ast);
04701 } else {
04702 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04703 }
04704 } else if (msgnum > -1) {
04705 if (strcmp(vmu->mailbox, mailbox)) {
04706
04707 struct ast_config *msg_cfg;
04708 const char *v;
04709 int inttime;
04710 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04711 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04712
04713 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04714 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04715 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04716 strcat(fromfile, ".txt");
04717 }
04718 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04719 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04720 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04721 }
04722
04723
04724
04725 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04726 struct timeval tv = { inttime, };
04727 struct ast_tm tm;
04728 ast_localtime(&tv, &tm, NULL);
04729 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04730 }
04731 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04732 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04733 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04734 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04735 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04736 date, origcallerid, origdate);
04737 ast_config_destroy(msg_cfg);
04738 } else {
04739 goto plain_message;
04740 }
04741 } else {
04742 plain_message:
04743 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04744 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04745 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04746 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04747 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04748 }
04749 } else {
04750 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04751 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04752 }
04753
04754 if (imap || attach_user_voicemail) {
04755 if (!ast_strlen_zero(attach2)) {
04756 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04757 ast_debug(5, "creating second attachment filename %s\n", filename);
04758 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04759 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04760 ast_debug(5, "creating attachment filename %s\n", filename);
04761 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04762 } else {
04763 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04764 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04765 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04766 }
04767 }
04768 ast_free(str1);
04769 ast_free(str2);
04770 }
04771
04772 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)
04773 {
04774 char tmpdir[256], newtmp[256];
04775 char fname[256];
04776 char tmpcmd[256];
04777 int tmpfd = -1;
04778 int soxstatus = 0;
04779
04780
04781 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04782
04783 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04784 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04785 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04786 tmpfd = mkstemp(newtmp);
04787 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04788 ast_debug(3, "newtmp: %s\n", newtmp);
04789 if (tmpfd > -1) {
04790 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04791 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04792 attach = newtmp;
04793 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04794 } else {
04795 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04796 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04797 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04798 }
04799 }
04800 }
04801 fprintf(p, "--%s" ENDL, bound);
04802 if (msgnum > -1)
04803 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04804 else
04805 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04806 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04807 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04808 if (msgnum > -1)
04809 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04810 else
04811 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04812 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04813 base_encode(fname, p);
04814 if (last)
04815 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04816 if (tmpfd > -1) {
04817 if (soxstatus == 0) {
04818 unlink(fname);
04819 }
04820 close(tmpfd);
04821 unlink(newtmp);
04822 }
04823 return 0;
04824 }
04825
04826 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)
04827 {
04828 FILE *p = NULL;
04829 char tmp[80] = "/tmp/astmail-XXXXXX";
04830 char tmp2[256];
04831 char *stringp;
04832
04833 if (vmu && ast_strlen_zero(vmu->email)) {
04834 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04835 return(0);
04836 }
04837
04838
04839 format = ast_strdupa(format);
04840 stringp = format;
04841 strsep(&stringp, "|");
04842
04843 if (!strcmp(format, "wav49"))
04844 format = "WAV";
04845 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));
04846
04847
04848 if ((p = vm_mkftemp(tmp)) == NULL) {
04849 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04850 return -1;
04851 } else {
04852 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04853 fclose(p);
04854 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04855 ast_safe_system(tmp2);
04856 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04857 }
04858 return 0;
04859 }
04860
04861 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)
04862 {
04863 char enc_cidnum[256], enc_cidname[256];
04864 char date[256];
04865 char host[MAXHOSTNAMELEN] = "";
04866 char who[256];
04867 char dur[PATH_MAX];
04868 char tmp[80] = "/tmp/astmail-XXXXXX";
04869 char tmp2[PATH_MAX];
04870 struct ast_tm tm;
04871 FILE *p;
04872 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04873
04874 if (!str1 || !str2) {
04875 ast_free(str1);
04876 ast_free(str2);
04877 return -1;
04878 }
04879
04880 if (cidnum) {
04881 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04882 }
04883 if (cidname) {
04884 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04885 }
04886
04887 if ((p = vm_mkftemp(tmp)) == NULL) {
04888 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04889 ast_free(str1);
04890 ast_free(str2);
04891 return -1;
04892 }
04893 gethostname(host, sizeof(host)-1);
04894 if (strchr(srcemail, '@')) {
04895 ast_copy_string(who, srcemail, sizeof(who));
04896 } else {
04897 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04898 }
04899 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04900 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04901 fprintf(p, "Date: %s\n", date);
04902
04903
04904 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04905
04906 if (!ast_strlen_zero(pagerfromstring)) {
04907 struct ast_channel *ast;
04908 if ((ast = ast_dummy_channel_alloc())) {
04909 char *ptr;
04910 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04911 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04912
04913 if (check_mime(ast_str_buffer(str1))) {
04914 int first_line = 1;
04915 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04916 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04917 *ptr = '\0';
04918 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04919 first_line = 0;
04920
04921 ast_str_set(&str2, 0, "%s", ptr + 1);
04922 }
04923 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04924 } else {
04925 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04926 }
04927 ast = ast_channel_unref(ast);
04928 } else {
04929 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04930 }
04931 } else {
04932 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04933 }
04934
04935 if (check_mime(vmu->fullname)) {
04936 int first_line = 1;
04937 char *ptr;
04938 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04939 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04940 *ptr = '\0';
04941 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04942 first_line = 0;
04943
04944 ast_str_set(&str2, 0, "%s", ptr + 1);
04945 }
04946 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04947 } else {
04948 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04949 }
04950
04951 if (!ast_strlen_zero(pagersubject)) {
04952 struct ast_channel *ast;
04953 if ((ast = ast_dummy_channel_alloc())) {
04954 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04955 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04956 if (check_mime(ast_str_buffer(str1))) {
04957 int first_line = 1;
04958 char *ptr;
04959 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04960 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04961 *ptr = '\0';
04962 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04963 first_line = 0;
04964
04965 ast_str_set(&str2, 0, "%s", ptr + 1);
04966 }
04967 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04968 } else {
04969 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04970 }
04971 ast = ast_channel_unref(ast);
04972 } else {
04973 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04974 }
04975 } else {
04976 if (ast_strlen_zero(flag)) {
04977 fprintf(p, "Subject: New VM\n\n");
04978 } else {
04979 fprintf(p, "Subject: New %s VM\n\n", flag);
04980 }
04981 }
04982
04983 if (pagerbody) {
04984 struct ast_channel *ast;
04985 if ((ast = ast_dummy_channel_alloc())) {
04986 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04987 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
04988 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04989 ast = ast_channel_unref(ast);
04990 } else {
04991 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04992 }
04993 } else {
04994 fprintf(p, "New %s long %s msg in box %s\n"
04995 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
04996 }
04997
04998 fclose(p);
04999 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05000 ast_safe_system(tmp2);
05001 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05002 ast_free(str1);
05003 ast_free(str2);
05004 return 0;
05005 }
05006
05007
05008
05009
05010
05011
05012
05013
05014
05015
05016 static int get_date(char *s, int len)
05017 {
05018 struct ast_tm tm;
05019 struct timeval t = ast_tvnow();
05020
05021 ast_localtime(&t, &tm, "UTC");
05022
05023 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05024 }
05025
05026 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05027 {
05028 int res;
05029 char fn[PATH_MAX];
05030 char dest[PATH_MAX];
05031
05032 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05033
05034 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05035 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05036 return -1;
05037 }
05038
05039 RETRIEVE(fn, -1, ext, context);
05040 if (ast_fileexists(fn, NULL, NULL) > 0) {
05041 res = ast_stream_and_wait(chan, fn, ecodes);
05042 if (res) {
05043 DISPOSE(fn, -1);
05044 return res;
05045 }
05046 } else {
05047
05048 DISPOSE(fn, -1);
05049 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05050 if (res)
05051 return res;
05052 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05053 if (res)
05054 return res;
05055 }
05056 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05057 return res;
05058 }
05059
05060 static void free_zone(struct vm_zone *z)
05061 {
05062 ast_free(z);
05063 }
05064
05065 #ifdef ODBC_STORAGE
05066 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05067 {
05068 int x = -1;
05069 int res;
05070 SQLHSTMT stmt = NULL;
05071 char sql[PATH_MAX];
05072 char rowdata[20];
05073 char tmp[PATH_MAX] = "";
05074 struct odbc_obj *obj = NULL;
05075 char *context;
05076 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05077
05078 if (newmsgs)
05079 *newmsgs = 0;
05080 if (oldmsgs)
05081 *oldmsgs = 0;
05082 if (urgentmsgs)
05083 *urgentmsgs = 0;
05084
05085
05086 if (ast_strlen_zero(mailbox))
05087 return 0;
05088
05089 ast_copy_string(tmp, mailbox, sizeof(tmp));
05090
05091 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05092 int u, n, o;
05093 char *next, *remaining = tmp;
05094 while ((next = strsep(&remaining, " ,"))) {
05095 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05096 return -1;
05097 }
05098 if (urgentmsgs) {
05099 *urgentmsgs += u;
05100 }
05101 if (newmsgs) {
05102 *newmsgs += n;
05103 }
05104 if (oldmsgs) {
05105 *oldmsgs += o;
05106 }
05107 }
05108 return 0;
05109 }
05110
05111 context = strchr(tmp, '@');
05112 if (context) {
05113 *context = '\0';
05114 context++;
05115 } else
05116 context = "default";
05117
05118 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05119 do {
05120 if (newmsgs) {
05121 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05122 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05123 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05124 break;
05125 }
05126 res = SQLFetch(stmt);
05127 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05128 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05129 break;
05130 }
05131 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05132 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05133 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05134 break;
05135 }
05136 *newmsgs = atoi(rowdata);
05137 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05138 }
05139
05140 if (oldmsgs) {
05141 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05142 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05143 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05144 break;
05145 }
05146 res = SQLFetch(stmt);
05147 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05148 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05149 break;
05150 }
05151 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05152 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05153 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05154 break;
05155 }
05156 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05157 *oldmsgs = atoi(rowdata);
05158 }
05159
05160 if (urgentmsgs) {
05161 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05162 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05163 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05164 break;
05165 }
05166 res = SQLFetch(stmt);
05167 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05168 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05169 break;
05170 }
05171 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05172 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05173 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05174 break;
05175 }
05176 *urgentmsgs = atoi(rowdata);
05177 }
05178
05179 x = 0;
05180 } while (0);
05181 } else {
05182 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05183 }
05184
05185 if (stmt) {
05186 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05187 }
05188 if (obj) {
05189 ast_odbc_release_obj(obj);
05190 }
05191 return x;
05192 }
05193
05194
05195
05196
05197
05198
05199
05200
05201
05202
05203 static int messagecount(const char *context, const char *mailbox, const char *folder)
05204 {
05205 struct odbc_obj *obj = NULL;
05206 int nummsgs = 0;
05207 int res;
05208 SQLHSTMT stmt = NULL;
05209 char sql[PATH_MAX];
05210 char rowdata[20];
05211 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05212 if (!folder)
05213 folder = "INBOX";
05214
05215 if (ast_strlen_zero(mailbox))
05216 return 0;
05217
05218 obj = ast_odbc_request_obj(odbc_database, 0);
05219 if (obj) {
05220 if (!strcmp(folder, "INBOX")) {
05221 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);
05222 } else {
05223 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05224 }
05225 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05226 if (!stmt) {
05227 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05228 goto yuck;
05229 }
05230 res = SQLFetch(stmt);
05231 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05232 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05233 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05234 goto yuck;
05235 }
05236 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05237 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05238 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05239 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05240 goto yuck;
05241 }
05242 nummsgs = atoi(rowdata);
05243 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05244 } else
05245 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05246
05247 yuck:
05248 if (obj)
05249 ast_odbc_release_obj(obj);
05250 return nummsgs;
05251 }
05252
05253
05254
05255
05256
05257
05258
05259
05260
05261 static int has_voicemail(const char *mailbox, const char *folder)
05262 {
05263 char tmp[256], *tmp2 = tmp, *box, *context;
05264 ast_copy_string(tmp, mailbox, sizeof(tmp));
05265 while ((context = box = strsep(&tmp2, ",&"))) {
05266 strsep(&context, "@");
05267 if (ast_strlen_zero(context))
05268 context = "default";
05269 if (messagecount(context, box, folder))
05270 return 1;
05271 }
05272 return 0;
05273 }
05274 #endif
05275 #ifndef IMAP_STORAGE
05276
05277
05278
05279
05280
05281
05282
05283
05284
05285
05286
05287
05288
05289
05290
05291
05292 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)
05293 {
05294 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05295 const char *frombox = mbox(vmu, imbox);
05296 const char *userfolder;
05297 int recipmsgnum;
05298 int res = 0;
05299
05300 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05301
05302 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05303 userfolder = "Urgent";
05304 } else {
05305 userfolder = "INBOX";
05306 }
05307
05308 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05309
05310 if (!dir)
05311 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05312 else
05313 ast_copy_string(fromdir, dir, sizeof(fromdir));
05314
05315 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05316 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05317
05318 if (vm_lock_path(todir))
05319 return ERROR_LOCK_PATH;
05320
05321 recipmsgnum = last_message_index(recip, todir) + 1;
05322 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05323 make_file(topath, sizeof(topath), todir, recipmsgnum);
05324 #ifndef ODBC_STORAGE
05325 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05326 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05327 } else {
05328 #endif
05329
05330
05331
05332 copy_plain_file(frompath, topath);
05333 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05334 vm_delete(topath);
05335 #ifndef ODBC_STORAGE
05336 }
05337 #endif
05338 } else {
05339 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05340 res = -1;
05341 }
05342 ast_unlock_path(todir);
05343 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05344 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05345 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05346 flag);
05347
05348 return res;
05349 }
05350 #endif
05351 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05352
05353 static int messagecount(const char *context, const char *mailbox, const char *folder)
05354 {
05355 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05356 }
05357
05358 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05359 {
05360 DIR *dir;
05361 struct dirent *de;
05362 char fn[256];
05363 int ret = 0;
05364
05365
05366 if (ast_strlen_zero(mailbox))
05367 return 0;
05368
05369 if (ast_strlen_zero(folder))
05370 folder = "INBOX";
05371 if (ast_strlen_zero(context))
05372 context = "default";
05373
05374 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05375
05376 if (!(dir = opendir(fn)))
05377 return 0;
05378
05379 while ((de = readdir(dir))) {
05380 if (!strncasecmp(de->d_name, "msg", 3)) {
05381 if (shortcircuit) {
05382 ret = 1;
05383 break;
05384 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05385 ret++;
05386 }
05387 }
05388 }
05389
05390 closedir(dir);
05391
05392 return ret;
05393 }
05394
05395
05396
05397
05398
05399
05400
05401
05402
05403
05404 static int has_voicemail(const char *mailbox, const char *folder)
05405 {
05406 char tmp[256], *tmp2 = tmp, *box, *context;
05407 ast_copy_string(tmp, mailbox, sizeof(tmp));
05408 if (ast_strlen_zero(folder)) {
05409 folder = "INBOX";
05410 }
05411 while ((box = strsep(&tmp2, ",&"))) {
05412 if ((context = strchr(box, '@')))
05413 *context++ = '\0';
05414 else
05415 context = "default";
05416 if (__has_voicemail(context, box, folder, 1))
05417 return 1;
05418
05419 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05420 return 1;
05421 }
05422 }
05423 return 0;
05424 }
05425
05426
05427 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05428 {
05429 char tmp[256];
05430 char *context;
05431
05432
05433 if (ast_strlen_zero(mailbox))
05434 return 0;
05435
05436 if (newmsgs)
05437 *newmsgs = 0;
05438 if (oldmsgs)
05439 *oldmsgs = 0;
05440 if (urgentmsgs)
05441 *urgentmsgs = 0;
05442
05443 if (strchr(mailbox, ',')) {
05444 int tmpnew, tmpold, tmpurgent;
05445 char *mb, *cur;
05446
05447 ast_copy_string(tmp, mailbox, sizeof(tmp));
05448 mb = tmp;
05449 while ((cur = strsep(&mb, ", "))) {
05450 if (!ast_strlen_zero(cur)) {
05451 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05452 return -1;
05453 else {
05454 if (newmsgs)
05455 *newmsgs += tmpnew;
05456 if (oldmsgs)
05457 *oldmsgs += tmpold;
05458 if (urgentmsgs)
05459 *urgentmsgs += tmpurgent;
05460 }
05461 }
05462 }
05463 return 0;
05464 }
05465
05466 ast_copy_string(tmp, mailbox, sizeof(tmp));
05467
05468 if ((context = strchr(tmp, '@')))
05469 *context++ = '\0';
05470 else
05471 context = "default";
05472
05473 if (newmsgs)
05474 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05475 if (oldmsgs)
05476 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05477 if (urgentmsgs)
05478 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05479
05480 return 0;
05481 }
05482
05483 #endif
05484
05485
05486 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05487 {
05488 int urgentmsgs = 0;
05489 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05490 if (newmsgs) {
05491 *newmsgs += urgentmsgs;
05492 }
05493 return res;
05494 }
05495
05496 static void run_externnotify(char *context, char *extension, const char *flag)
05497 {
05498 char arguments[255];
05499 char ext_context[256] = "";
05500 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05501 struct ast_smdi_mwi_message *mwi_msg;
05502
05503 if (!ast_strlen_zero(context))
05504 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05505 else
05506 ast_copy_string(ext_context, extension, sizeof(ext_context));
05507
05508 if (smdi_iface) {
05509 if (ast_app_has_voicemail(ext_context, NULL))
05510 ast_smdi_mwi_set(smdi_iface, extension);
05511 else
05512 ast_smdi_mwi_unset(smdi_iface, extension);
05513
05514 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05515 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05516 if (!strncmp(mwi_msg->cause, "INV", 3))
05517 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05518 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05519 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05520 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05521 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05522 } else {
05523 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05524 }
05525 }
05526
05527 if (!ast_strlen_zero(externnotify)) {
05528 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05529 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05530 } else {
05531 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05532 ast_debug(1, "Executing %s\n", arguments);
05533 ast_safe_system(arguments);
05534 }
05535 }
05536 }
05537
05538
05539
05540
05541
05542
05543 struct leave_vm_options {
05544 unsigned int flags;
05545 signed char record_gain;
05546 char *exitcontext;
05547 };
05548
05549
05550
05551
05552
05553
05554
05555
05556
05557
05558
05559 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05560 {
05561 #ifdef IMAP_STORAGE
05562 int newmsgs, oldmsgs;
05563 #else
05564 char urgdir[PATH_MAX];
05565 #endif
05566 char txtfile[PATH_MAX];
05567 char tmptxtfile[PATH_MAX];
05568 struct vm_state *vms = NULL;
05569 char callerid[256];
05570 FILE *txt;
05571 char date[256];
05572 int txtdes;
05573 int res = 0;
05574 int msgnum;
05575 int duration = 0;
05576 int sound_duration = 0;
05577 int ausemacro = 0;
05578 int ousemacro = 0;
05579 int ouseexten = 0;
05580 char tmpdur[16];
05581 char priority[16];
05582 char origtime[16];
05583 char dir[PATH_MAX];
05584 char tmpdir[PATH_MAX];
05585 char fn[PATH_MAX];
05586 char prefile[PATH_MAX] = "";
05587 char tempfile[PATH_MAX] = "";
05588 char ext_context[256] = "";
05589 char fmt[80];
05590 char *context;
05591 char ecodes[17] = "#";
05592 struct ast_str *tmp = ast_str_create(16);
05593 char *tmpptr;
05594 struct ast_vm_user *vmu;
05595 struct ast_vm_user svm;
05596 const char *category = NULL;
05597 const char *code;
05598 const char *alldtmf = "0123456789ABCD*#";
05599 char flag[80];
05600
05601 if (!tmp) {
05602 return -1;
05603 }
05604
05605 ast_str_set(&tmp, 0, "%s", ext);
05606 ext = ast_str_buffer(tmp);
05607 if ((context = strchr(ext, '@'))) {
05608 *context++ = '\0';
05609 tmpptr = strchr(context, '&');
05610 } else {
05611 tmpptr = strchr(ext, '&');
05612 }
05613
05614 if (tmpptr)
05615 *tmpptr++ = '\0';
05616
05617 ast_channel_lock(chan);
05618 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05619 category = ast_strdupa(category);
05620 }
05621 ast_channel_unlock(chan);
05622
05623 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05624 ast_copy_string(flag, "Urgent", sizeof(flag));
05625 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05626 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05627 } else {
05628 flag[0] = '\0';
05629 }
05630
05631 ast_debug(3, "Before find_user\n");
05632 if (!(vmu = find_user(&svm, context, ext))) {
05633 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05634 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05635 ast_free(tmp);
05636 return res;
05637 }
05638
05639 if (strcmp(vmu->context, "default"))
05640 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05641 else
05642 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05643
05644
05645
05646
05647
05648
05649 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05650 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05651 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05652 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05653 }
05654
05655
05656
05657
05658 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05659 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05660 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05661 ast_free(tmp);
05662 return -1;
05663 }
05664 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05665 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05666 ast_copy_string(prefile, tempfile, sizeof(prefile));
05667
05668 DISPOSE(tempfile, -1);
05669
05670 #ifndef IMAP_STORAGE
05671 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05672 #else
05673 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05674 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05675 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05676 }
05677 #endif
05678
05679
05680 if (ast_test_flag(vmu, VM_OPERATOR)) {
05681 if (!ast_strlen_zero(vmu->exit)) {
05682 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05683 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05684 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05685 ouseexten = 1;
05686 }
05687 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05688 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05689 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05690 ouseexten = 1;
05691 } else if (!ast_strlen_zero(chan->macrocontext)
05692 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05693 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05694 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05695 ousemacro = 1;
05696 }
05697 }
05698
05699 if (!ast_strlen_zero(vmu->exit)) {
05700 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05701 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05702 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05703 }
05704 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05705 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05706 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05707 } else if (!ast_strlen_zero(chan->macrocontext)
05708 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05709 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05710 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05711 ausemacro = 1;
05712 }
05713
05714 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05715 for (code = alldtmf; *code; code++) {
05716 char e[2] = "";
05717 e[0] = *code;
05718 if (strchr(ecodes, e[0]) == NULL
05719 && ast_canmatch_extension(chan,
05720 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05721 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05722 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05723 }
05724 }
05725 }
05726
05727
05728 if (!ast_strlen_zero(prefile)) {
05729 #ifdef ODBC_STORAGE
05730 int success =
05731 #endif
05732 RETRIEVE(prefile, -1, ext, context);
05733 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05734 if (ast_streamfile(chan, prefile, chan->language) > -1)
05735 res = ast_waitstream(chan, ecodes);
05736 #ifdef ODBC_STORAGE
05737 if (success == -1) {
05738
05739 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05740 store_file(prefile, vmu->mailbox, vmu->context, -1);
05741 }
05742 #endif
05743 } else {
05744 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05745 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05746 }
05747 DISPOSE(prefile, -1);
05748 if (res < 0) {
05749 ast_debug(1, "Hang up during prefile playback\n");
05750 free_user(vmu);
05751 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05752 ast_free(tmp);
05753 return -1;
05754 }
05755 }
05756 if (res == '#') {
05757
05758 ast_set_flag(options, OPT_SILENT);
05759 res = 0;
05760 }
05761
05762 if (vmu->maxmsg == 0) {
05763 if (option_debug > 2)
05764 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05765 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05766 goto leave_vm_out;
05767 }
05768 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05769 res = ast_stream_and_wait(chan, INTRO, ecodes);
05770 if (res == '#') {
05771 ast_set_flag(options, OPT_SILENT);
05772 res = 0;
05773 }
05774 }
05775 if (res > 0)
05776 ast_stopstream(chan);
05777
05778
05779 if (res == '*') {
05780 chan->exten[0] = 'a';
05781 chan->exten[1] = '\0';
05782 if (!ast_strlen_zero(vmu->exit)) {
05783 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05784 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05785 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05786 }
05787 chan->priority = 0;
05788 free_user(vmu);
05789 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05790 ast_free(tmp);
05791 return 0;
05792 }
05793
05794
05795 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05796 transfer:
05797 if (ouseexten || ousemacro) {
05798 chan->exten[0] = 'o';
05799 chan->exten[1] = '\0';
05800 if (!ast_strlen_zero(vmu->exit)) {
05801 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05802 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05803 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05804 }
05805 ast_play_and_wait(chan, "transfer");
05806 chan->priority = 0;
05807 free_user(vmu);
05808 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05809 }
05810 ast_free(tmp);
05811 return OPERATOR_EXIT;
05812 }
05813
05814
05815 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05816 if (!ast_strlen_zero(options->exitcontext)) {
05817 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05818 }
05819 free_user(vmu);
05820 ast_free(tmp);
05821 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05822 return res;
05823 }
05824
05825 if (res < 0) {
05826 free_user(vmu);
05827 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05828 ast_free(tmp);
05829 return -1;
05830 }
05831
05832 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05833 if (!ast_strlen_zero(fmt)) {
05834 msgnum = 0;
05835
05836 #ifdef IMAP_STORAGE
05837
05838
05839 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05840 if (res < 0) {
05841 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05842 ast_free(tmp);
05843 return -1;
05844 }
05845 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05846
05847
05848
05849
05850 if (!(vms = create_vm_state_from_user(vmu))) {
05851 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05852 ast_free(tmp);
05853 return -1;
05854 }
05855 }
05856 vms->newmessages++;
05857
05858
05859 msgnum = newmsgs + oldmsgs;
05860 ast_debug(3, "Messagecount set to %d\n", msgnum);
05861 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05862
05863 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05864
05865 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05866 goto leave_vm_out;
05867 }
05868 #else
05869 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05870 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05871 if (!res)
05872 res = ast_waitstream(chan, "");
05873 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05874 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05875 inprocess_count(vmu->mailbox, vmu->context, -1);
05876 goto leave_vm_out;
05877 }
05878
05879 #endif
05880 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05881 txtdes = mkstemp(tmptxtfile);
05882 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05883 if (txtdes < 0) {
05884 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05885 if (!res)
05886 res = ast_waitstream(chan, "");
05887 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05888 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05889 inprocess_count(vmu->mailbox, vmu->context, -1);
05890 goto leave_vm_out;
05891 }
05892
05893
05894 if (res >= 0) {
05895
05896 res = ast_stream_and_wait(chan, "beep", "");
05897 }
05898
05899
05900 if (ast_check_realtime("voicemail_data")) {
05901 snprintf(priority, sizeof(priority), "%d", chan->priority);
05902 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05903 get_date(date, sizeof(date));
05904 ast_callerid_merge(callerid, sizeof(callerid),
05905 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05906 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05907 "Unknown");
05908 ast_store_realtime("voicemail_data",
05909 "origmailbox", ext,
05910 "context", chan->context,
05911 "macrocontext", chan->macrocontext,
05912 "exten", chan->exten,
05913 "priority", priority,
05914 "callerchan", chan->name,
05915 "callerid", callerid,
05916 "origdate", date,
05917 "origtime", origtime,
05918 "category", S_OR(category, ""),
05919 "filename", tmptxtfile,
05920 SENTINEL);
05921 }
05922
05923
05924 txt = fdopen(txtdes, "w+");
05925 if (txt) {
05926 get_date(date, sizeof(date));
05927 ast_callerid_merge(callerid, sizeof(callerid),
05928 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05929 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05930 "Unknown");
05931 fprintf(txt,
05932 ";\n"
05933 "; Message Information file\n"
05934 ";\n"
05935 "[message]\n"
05936 "origmailbox=%s\n"
05937 "context=%s\n"
05938 "macrocontext=%s\n"
05939 "exten=%s\n"
05940 "rdnis=%s\n"
05941 "priority=%d\n"
05942 "callerchan=%s\n"
05943 "callerid=%s\n"
05944 "origdate=%s\n"
05945 "origtime=%ld\n"
05946 "category=%s\n",
05947 ext,
05948 chan->context,
05949 chan->macrocontext,
05950 chan->exten,
05951 S_COR(chan->redirecting.from.number.valid,
05952 chan->redirecting.from.number.str, "unknown"),
05953 chan->priority,
05954 chan->name,
05955 callerid,
05956 date, (long) time(NULL),
05957 category ? category : "");
05958 } else {
05959 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05960 inprocess_count(vmu->mailbox, vmu->context, -1);
05961 if (ast_check_realtime("voicemail_data")) {
05962 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05963 }
05964 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05965 goto leave_vm_out;
05966 }
05967 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
05968
05969 if (txt) {
05970 fprintf(txt, "flag=%s\n", flag);
05971 if (sound_duration < vmu->minsecs) {
05972 fclose(txt);
05973 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
05974 ast_filedelete(tmptxtfile, NULL);
05975 unlink(tmptxtfile);
05976 if (ast_check_realtime("voicemail_data")) {
05977 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05978 }
05979 inprocess_count(vmu->mailbox, vmu->context, -1);
05980 } else {
05981 fprintf(txt, "duration=%d\n", duration);
05982 fclose(txt);
05983 if (vm_lock_path(dir)) {
05984 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05985
05986 ast_filedelete(tmptxtfile, NULL);
05987 unlink(tmptxtfile);
05988 inprocess_count(vmu->mailbox, vmu->context, -1);
05989 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
05990 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
05991 unlink(tmptxtfile);
05992 ast_unlock_path(dir);
05993 inprocess_count(vmu->mailbox, vmu->context, -1);
05994 if (ast_check_realtime("voicemail_data")) {
05995 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05996 }
05997 } else {
05998 #ifndef IMAP_STORAGE
05999 msgnum = last_message_index(vmu, dir) + 1;
06000 #endif
06001 make_file(fn, sizeof(fn), dir, msgnum);
06002
06003
06004 #ifndef IMAP_STORAGE
06005 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06006 #else
06007 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06008 #endif
06009
06010 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06011 ast_filerename(tmptxtfile, fn, NULL);
06012 rename(tmptxtfile, txtfile);
06013 inprocess_count(vmu->mailbox, vmu->context, -1);
06014
06015
06016
06017 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06018 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06019
06020 ast_unlock_path(dir);
06021 if (ast_check_realtime("voicemail_data")) {
06022 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06023 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06024 }
06025
06026
06027
06028 if (ast_fileexists(fn, NULL, NULL) > 0) {
06029 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06030 }
06031
06032
06033 while (tmpptr) {
06034 struct ast_vm_user recipu, *recip;
06035 char *exten, *cntx;
06036
06037 exten = strsep(&tmpptr, "&");
06038 cntx = strchr(exten, '@');
06039 if (cntx) {
06040 *cntx = '\0';
06041 cntx++;
06042 }
06043 if ((recip = find_user(&recipu, cntx, exten))) {
06044 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06045 free_user(recip);
06046 }
06047 }
06048 #ifndef IMAP_STORAGE
06049 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06050
06051 char sfn[PATH_MAX];
06052 char dfn[PATH_MAX];
06053 int x;
06054
06055 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06056 x = last_message_index(vmu, urgdir) + 1;
06057 make_file(sfn, sizeof(sfn), dir, msgnum);
06058 make_file(dfn, sizeof(dfn), urgdir, x);
06059 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06060 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06061
06062 ast_copy_string(fn, dfn, sizeof(fn));
06063 msgnum = x;
06064 }
06065 #endif
06066
06067 if (ast_fileexists(fn, NULL, NULL)) {
06068 #ifdef IMAP_STORAGE
06069 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06070 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06071 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06072 flag);
06073 #else
06074 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06075 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06076 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06077 flag);
06078 #endif
06079 }
06080
06081
06082 if (ast_fileexists(fn, NULL, NULL)) {
06083 DISPOSE(dir, msgnum);
06084 }
06085 }
06086 }
06087 } else {
06088 inprocess_count(vmu->mailbox, vmu->context, -1);
06089 }
06090 if (res == '0') {
06091 goto transfer;
06092 } else if (res > 0 && res != 't')
06093 res = 0;
06094
06095 if (sound_duration < vmu->minsecs)
06096
06097 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06098 else
06099 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06100 } else
06101 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06102 leave_vm_out:
06103 free_user(vmu);
06104
06105 #ifdef IMAP_STORAGE
06106
06107 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06108 if (expungeonhangup == 1) {
06109 ast_mutex_lock(&vms->lock);
06110 #ifdef HAVE_IMAP_TK2006
06111 if (LEVELUIDPLUS (vms->mailstream)) {
06112 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06113 } else
06114 #endif
06115 mail_expunge(vms->mailstream);
06116 ast_mutex_unlock(&vms->lock);
06117 }
06118 #endif
06119
06120 ast_free(tmp);
06121 return res;
06122 }
06123
06124 #if !defined(IMAP_STORAGE)
06125 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06126 {
06127
06128
06129 int x, dest;
06130 char sfn[PATH_MAX];
06131 char dfn[PATH_MAX];
06132
06133 if (vm_lock_path(dir)) {
06134 return ERROR_LOCK_PATH;
06135 }
06136
06137 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06138 make_file(sfn, sizeof(sfn), dir, x);
06139 if (EXISTS(dir, x, sfn, NULL)) {
06140
06141 if (x != dest) {
06142 make_file(dfn, sizeof(dfn), dir, dest);
06143 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06144 }
06145
06146 dest++;
06147 }
06148 }
06149 ast_unlock_path(dir);
06150
06151 return dest;
06152 }
06153 #endif
06154
06155 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06156 {
06157 int d;
06158 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06159 return d;
06160 }
06161
06162 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06163 {
06164 #ifdef IMAP_STORAGE
06165
06166
06167 char sequence[10];
06168 char mailbox[256];
06169 int res;
06170
06171
06172 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06173
06174 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06175 ast_mutex_lock(&vms->lock);
06176
06177 if (box == OLD_FOLDER) {
06178 mail_setflag(vms->mailstream, sequence, "\\Seen");
06179 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06180 } else if (box == NEW_FOLDER) {
06181 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06182 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06183 }
06184 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06185 ast_mutex_unlock(&vms->lock);
06186 return 0;
06187 }
06188
06189 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06190 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06191 if (mail_create(vms->mailstream, mailbox) == NIL)
06192 ast_debug(5, "Folder exists.\n");
06193 else
06194 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06195 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06196 ast_mutex_unlock(&vms->lock);
06197 return res;
06198 #else
06199 char *dir = vms->curdir;
06200 char *username = vms->username;
06201 char *context = vmu->context;
06202 char sfn[PATH_MAX];
06203 char dfn[PATH_MAX];
06204 char ddir[PATH_MAX];
06205 const char *dbox = mbox(vmu, box);
06206 int x, i;
06207 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06208
06209 if (vm_lock_path(ddir))
06210 return ERROR_LOCK_PATH;
06211
06212 x = last_message_index(vmu, ddir) + 1;
06213
06214 if (box == 10 && x >= vmu->maxdeletedmsg) {
06215 x--;
06216 for (i = 1; i <= x; i++) {
06217
06218 make_file(sfn, sizeof(sfn), ddir, i);
06219 make_file(dfn, sizeof(dfn), ddir, i - 1);
06220 if (EXISTS(ddir, i, sfn, NULL)) {
06221 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06222 } else
06223 break;
06224 }
06225 } else {
06226 if (x >= vmu->maxmsg) {
06227 ast_unlock_path(ddir);
06228 return -1;
06229 }
06230 }
06231 make_file(sfn, sizeof(sfn), dir, msg);
06232 make_file(dfn, sizeof(dfn), ddir, x);
06233 if (strcmp(sfn, dfn)) {
06234 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06235 }
06236 ast_unlock_path(ddir);
06237 #endif
06238 return 0;
06239 }
06240
06241 static int adsi_logo(unsigned char *buf)
06242 {
06243 int bytes = 0;
06244 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06245 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06246 return bytes;
06247 }
06248
06249 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06250 {
06251 unsigned char buf[256];
06252 int bytes = 0;
06253 int x;
06254 char num[5];
06255
06256 *useadsi = 0;
06257 bytes += ast_adsi_data_mode(buf + bytes);
06258 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06259
06260 bytes = 0;
06261 bytes += adsi_logo(buf);
06262 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06263 #ifdef DISPLAY
06264 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06265 #endif
06266 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06267 bytes += ast_adsi_data_mode(buf + bytes);
06268 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06269
06270 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06271 bytes = 0;
06272 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06273 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06274 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06275 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06276 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06277 return 0;
06278 }
06279
06280 #ifdef DISPLAY
06281
06282 bytes = 0;
06283 bytes += ast_adsi_logo(buf);
06284 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06285 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06286 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06287 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06288 #endif
06289 bytes = 0;
06290 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06291 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06292 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06293 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06294 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06295 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06296 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06297
06298 #ifdef DISPLAY
06299
06300 bytes = 0;
06301 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06302 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06303
06304 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06305 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06306 #endif
06307
06308 bytes = 0;
06309
06310 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06311 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06312 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06313 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06314 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06315 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06316 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06317
06318 #ifdef DISPLAY
06319
06320 bytes = 0;
06321 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06322 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06323 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06324 #endif
06325
06326 bytes = 0;
06327 for (x = 0; x < 5; x++) {
06328 snprintf(num, sizeof(num), "%d", x);
06329 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06330 }
06331 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06332 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06333
06334 #ifdef DISPLAY
06335
06336 bytes = 0;
06337 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06338 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06339 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06340 #endif
06341
06342 if (ast_adsi_end_download(chan)) {
06343 bytes = 0;
06344 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06345 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06346 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06347 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06348 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06349 return 0;
06350 }
06351 bytes = 0;
06352 bytes += ast_adsi_download_disconnect(buf + bytes);
06353 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06354 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06355
06356 ast_debug(1, "Done downloading scripts...\n");
06357
06358 #ifdef DISPLAY
06359
06360 bytes = 0;
06361 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06362 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06363 #endif
06364 ast_debug(1, "Restarting session...\n");
06365
06366 bytes = 0;
06367
06368 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06369 *useadsi = 1;
06370 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06371 } else
06372 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06373
06374 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06375 return 0;
06376 }
06377
06378 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06379 {
06380 int x;
06381 if (!ast_adsi_available(chan))
06382 return;
06383 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06384 if (x < 0)
06385 return;
06386 if (!x) {
06387 if (adsi_load_vmail(chan, useadsi)) {
06388 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06389 return;
06390 }
06391 } else
06392 *useadsi = 1;
06393 }
06394
06395 static void adsi_login(struct ast_channel *chan)
06396 {
06397 unsigned char buf[256];
06398 int bytes = 0;
06399 unsigned char keys[8];
06400 int x;
06401 if (!ast_adsi_available(chan))
06402 return;
06403
06404 for (x = 0; x < 8; x++)
06405 keys[x] = 0;
06406
06407 keys[3] = ADSI_KEY_APPS + 3;
06408
06409 bytes += adsi_logo(buf + bytes);
06410 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06411 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06412 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06413 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06414 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06415 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06416 bytes += ast_adsi_set_keys(buf + bytes, keys);
06417 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06418 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06419 }
06420
06421 static void adsi_password(struct ast_channel *chan)
06422 {
06423 unsigned char buf[256];
06424 int bytes = 0;
06425 unsigned char keys[8];
06426 int x;
06427 if (!ast_adsi_available(chan))
06428 return;
06429
06430 for (x = 0; x < 8; x++)
06431 keys[x] = 0;
06432
06433 keys[3] = ADSI_KEY_APPS + 3;
06434
06435 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06436 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06437 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06438 bytes += ast_adsi_set_keys(buf + bytes, keys);
06439 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06440 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06441 }
06442
06443 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06444 {
06445 unsigned char buf[256];
06446 int bytes = 0;
06447 unsigned char keys[8];
06448 int x, y;
06449
06450 if (!ast_adsi_available(chan))
06451 return;
06452
06453 for (x = 0; x < 5; x++) {
06454 y = ADSI_KEY_APPS + 12 + start + x;
06455 if (y > ADSI_KEY_APPS + 12 + 4)
06456 y = 0;
06457 keys[x] = ADSI_KEY_SKT | y;
06458 }
06459 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06460 keys[6] = 0;
06461 keys[7] = 0;
06462
06463 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06464 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06465 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06466 bytes += ast_adsi_set_keys(buf + bytes, keys);
06467 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06468
06469 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06470 }
06471
06472 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06473 {
06474 int bytes = 0;
06475 unsigned char buf[256];
06476 char buf1[256], buf2[256];
06477 char fn2[PATH_MAX];
06478
06479 char cid[256] = "";
06480 char *val;
06481 char *name, *num;
06482 char datetime[21] = "";
06483 FILE *f;
06484
06485 unsigned char keys[8];
06486
06487 int x;
06488
06489 if (!ast_adsi_available(chan))
06490 return;
06491
06492
06493 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06494 f = fopen(fn2, "r");
06495 if (f) {
06496 while (!feof(f)) {
06497 if (!fgets((char *) buf, sizeof(buf), f)) {
06498 continue;
06499 }
06500 if (!feof(f)) {
06501 char *stringp = NULL;
06502 stringp = (char *) buf;
06503 strsep(&stringp, "=");
06504 val = strsep(&stringp, "=");
06505 if (!ast_strlen_zero(val)) {
06506 if (!strcmp((char *) buf, "callerid"))
06507 ast_copy_string(cid, val, sizeof(cid));
06508 if (!strcmp((char *) buf, "origdate"))
06509 ast_copy_string(datetime, val, sizeof(datetime));
06510 }
06511 }
06512 }
06513 fclose(f);
06514 }
06515
06516 for (x = 0; x < 5; x++)
06517 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06518 keys[6] = 0x0;
06519 keys[7] = 0x0;
06520
06521 if (!vms->curmsg) {
06522
06523 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06524 }
06525 if (vms->curmsg >= vms->lastmsg) {
06526
06527 if (vms->curmsg) {
06528
06529 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06530 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06531
06532 } else {
06533
06534 keys[3] = 1;
06535 }
06536 }
06537
06538 if (!ast_strlen_zero(cid)) {
06539 ast_callerid_parse(cid, &name, &num);
06540 if (!name)
06541 name = num;
06542 } else
06543 name = "Unknown Caller";
06544
06545
06546 #ifdef IMAP_STORAGE
06547 ast_mutex_lock(&vms->lock);
06548 #endif
06549 if (vms->deleted[vms->curmsg]) {
06550 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06551 }
06552 #ifdef IMAP_STORAGE
06553 ast_mutex_unlock(&vms->lock);
06554 #endif
06555
06556
06557 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06558 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06559 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06560 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06561
06562 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06563 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06564 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06565 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06566 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06567 bytes += ast_adsi_set_keys(buf + bytes, keys);
06568 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06569
06570 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06571 }
06572
06573 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06574 {
06575 int bytes = 0;
06576 unsigned char buf[256];
06577 unsigned char keys[8];
06578
06579 int x;
06580
06581 if (!ast_adsi_available(chan))
06582 return;
06583
06584
06585 for (x = 0; x < 5; x++)
06586 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06587
06588 keys[6] = 0x0;
06589 keys[7] = 0x0;
06590
06591 if (!vms->curmsg) {
06592
06593 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06594 }
06595 if (vms->curmsg >= vms->lastmsg) {
06596
06597 if (vms->curmsg) {
06598
06599 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06600 } else {
06601
06602 keys[3] = 1;
06603 }
06604 }
06605
06606
06607 #ifdef IMAP_STORAGE
06608 ast_mutex_lock(&vms->lock);
06609 #endif
06610 if (vms->deleted[vms->curmsg]) {
06611 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06612 }
06613 #ifdef IMAP_STORAGE
06614 ast_mutex_unlock(&vms->lock);
06615 #endif
06616
06617
06618 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06619 bytes += ast_adsi_set_keys(buf + bytes, keys);
06620 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06621
06622 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06623 }
06624
06625 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06626 {
06627 unsigned char buf[256] = "";
06628 char buf1[256] = "", buf2[256] = "";
06629 int bytes = 0;
06630 unsigned char keys[8];
06631 int x;
06632
06633 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06634 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06635 if (!ast_adsi_available(chan))
06636 return;
06637 if (vms->newmessages) {
06638 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06639 if (vms->oldmessages) {
06640 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06641 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06642 } else {
06643 snprintf(buf2, sizeof(buf2), "%s.", newm);
06644 }
06645 } else if (vms->oldmessages) {
06646 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06647 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06648 } else {
06649 strcpy(buf1, "You have no messages.");
06650 buf2[0] = ' ';
06651 buf2[1] = '\0';
06652 }
06653 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06654 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06655 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06656
06657 for (x = 0; x < 6; x++)
06658 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06659 keys[6] = 0;
06660 keys[7] = 0;
06661
06662
06663 if (vms->lastmsg < 0)
06664 keys[0] = 1;
06665 bytes += ast_adsi_set_keys(buf + bytes, keys);
06666
06667 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06668
06669 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06670 }
06671
06672 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06673 {
06674 unsigned char buf[256] = "";
06675 char buf1[256] = "", buf2[256] = "";
06676 int bytes = 0;
06677 unsigned char keys[8];
06678 int x;
06679
06680 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06681
06682 if (!ast_adsi_available(chan))
06683 return;
06684
06685
06686 for (x = 0; x < 6; x++)
06687 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06688
06689 keys[6] = 0;
06690 keys[7] = 0;
06691
06692 if ((vms->lastmsg + 1) < 1)
06693 keys[0] = 0;
06694
06695 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06696 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06697
06698 if (vms->lastmsg + 1)
06699 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06700 else
06701 strcpy(buf2, "no messages.");
06702 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06703 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06704 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06705 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06706 bytes += ast_adsi_set_keys(buf + bytes, keys);
06707
06708 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06709
06710 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06711
06712 }
06713
06714
06715
06716
06717
06718
06719
06720
06721
06722
06723
06724
06725
06726
06727
06728 static void adsi_goodbye(struct ast_channel *chan)
06729 {
06730 unsigned char buf[256];
06731 int bytes = 0;
06732
06733 if (!ast_adsi_available(chan))
06734 return;
06735 bytes += adsi_logo(buf + bytes);
06736 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06737 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06738 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06739 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06740
06741 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06742 }
06743
06744
06745
06746
06747
06748 static int get_folder(struct ast_channel *chan, int start)
06749 {
06750 int x;
06751 int d;
06752 char fn[PATH_MAX];
06753 d = ast_play_and_wait(chan, "vm-press");
06754 if (d)
06755 return d;
06756 for (x = start; x < 5; x++) {
06757 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06758 return d;
06759 d = ast_play_and_wait(chan, "vm-for");
06760 if (d)
06761 return d;
06762 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06763
06764
06765
06766
06767 if (x == 0) {
06768 if (ast_fileexists(fn, NULL, NULL)) {
06769 d = vm_play_folder_name(chan, fn);
06770 } else {
06771 ast_verb(1, "failed to find %s\n", fn);
06772 d = vm_play_folder_name(chan, "vm-INBOX");
06773 }
06774 } else {
06775 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06776 d = vm_play_folder_name(chan, fn);
06777 }
06778
06779 if (d)
06780 return d;
06781 d = ast_waitfordigit(chan, 500);
06782 if (d)
06783 return d;
06784 }
06785
06786 d = ast_play_and_wait(chan, "vm-tocancel");
06787 if (d)
06788 return d;
06789 d = ast_waitfordigit(chan, 4000);
06790 return d;
06791 }
06792
06793
06794
06795
06796
06797
06798
06799
06800
06801
06802
06803
06804
06805 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06806 {
06807 int res = 0;
06808 int loops = 0;
06809
06810 res = ast_play_and_wait(chan, fn);
06811 while (((res < '0') || (res > '9')) &&
06812 (res != '#') && (res >= 0) &&
06813 loops < 4) {
06814 res = get_folder(chan, 0);
06815 loops++;
06816 }
06817 if (loops == 4) {
06818 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06819 return '#';
06820 }
06821 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06822 return res;
06823 }
06824
06825
06826
06827
06828
06829
06830
06831
06832
06833
06834
06835
06836
06837
06838
06839
06840
06841
06842
06843 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06844 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06845 {
06846 int cmd = 0;
06847 int retries = 0, prepend_duration = 0, already_recorded = 0;
06848 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06849 char textfile[PATH_MAX];
06850 struct ast_config *msg_cfg;
06851 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06852 #ifndef IMAP_STORAGE
06853 signed char zero_gain = 0;
06854 #endif
06855 const char *duration_str;
06856
06857
06858 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06859 strcpy(textfile, msgfile);
06860 strcpy(backup, msgfile);
06861 strcpy(backup_textfile, msgfile);
06862 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06863 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06864 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06865
06866 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06867 *duration = atoi(duration_str);
06868 } else {
06869 *duration = 0;
06870 }
06871
06872 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06873 if (cmd)
06874 retries = 0;
06875 switch (cmd) {
06876 case '1':
06877
06878 #ifdef IMAP_STORAGE
06879
06880 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06881 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06882 ast_play_and_wait(chan, INTRO);
06883 ast_play_and_wait(chan, "beep");
06884 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06885 if (cmd == -1) {
06886 break;
06887 }
06888 cmd = 't';
06889 #else
06890
06891
06892
06893 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06894 strcpy(textfile, msgfile);
06895 strncat(textfile, ".txt", sizeof(textfile) - 1);
06896 *duration = 0;
06897
06898
06899 if (!msg_cfg) {
06900 cmd = 0;
06901 break;
06902 }
06903
06904
06905 #ifndef IMAP_STORAGE
06906 if (already_recorded) {
06907 ast_filecopy(backup, msgfile, NULL);
06908 copy(backup_textfile, textfile);
06909 }
06910 else {
06911 ast_filecopy(msgfile, backup, NULL);
06912 copy(textfile, backup_textfile);
06913 }
06914 #endif
06915 already_recorded = 1;
06916
06917 if (record_gain)
06918 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06919
06920 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06921
06922 if (cmd == 'S') {
06923 ast_stream_and_wait(chan, vm_pls_try_again, "");
06924 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06925 ast_filerename(backup, msgfile, NULL);
06926 }
06927
06928 if (record_gain)
06929 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06930
06931
06932 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06933 *duration = atoi(duration_str);
06934
06935 if (prepend_duration) {
06936 struct ast_category *msg_cat;
06937
06938 char duration_buf[12];
06939
06940 *duration += prepend_duration;
06941 msg_cat = ast_category_get(msg_cfg, "message");
06942 snprintf(duration_buf, 11, "%ld", *duration);
06943 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06944 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06945 }
06946 }
06947
06948 #endif
06949 break;
06950 case '2':
06951
06952 #ifdef IMAP_STORAGE
06953 *vms->introfn = '\0';
06954 #endif
06955 cmd = 't';
06956 break;
06957 case '*':
06958 cmd = '*';
06959 break;
06960 default:
06961
06962 already_recorded = 0;
06963
06964 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06965
06966 if (!cmd) {
06967 cmd = ast_play_and_wait(chan, "vm-starmain");
06968
06969 }
06970 if (!cmd) {
06971 cmd = ast_waitfordigit(chan, 6000);
06972 }
06973 if (!cmd) {
06974 retries++;
06975 }
06976 if (retries > 3) {
06977 cmd = '*';
06978 }
06979 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
06980 }
06981 }
06982
06983 if (msg_cfg)
06984 ast_config_destroy(msg_cfg);
06985 if (prepend_duration)
06986 *duration = prepend_duration;
06987
06988 if (already_recorded && cmd == -1) {
06989
06990 ast_filerename(backup, msgfile, NULL);
06991 rename(backup_textfile, textfile);
06992 }
06993
06994 if (cmd == 't' || cmd == 'S')
06995 cmd = 0;
06996 return cmd;
06997 }
06998
06999 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07000 {
07001 struct ast_event *event;
07002 char *mailbox, *context;
07003
07004
07005 context = mailbox = ast_strdupa(box);
07006 strsep(&context, "@");
07007 if (ast_strlen_zero(context))
07008 context = "default";
07009
07010 if (!(event = ast_event_new(AST_EVENT_MWI,
07011 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07012 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07013 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07014 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07015 AST_EVENT_IE_END))) {
07016 return;
07017 }
07018
07019 ast_event_queue_and_cache(event);
07020 }
07021
07022
07023
07024
07025
07026
07027
07028
07029
07030
07031
07032
07033
07034
07035
07036 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)
07037 {
07038 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07039 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07040 const char *category;
07041 char *myserveremail = serveremail;
07042
07043 ast_channel_lock(chan);
07044 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07045 category = ast_strdupa(category);
07046 }
07047 ast_channel_unlock(chan);
07048
07049 #ifndef IMAP_STORAGE
07050 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07051 #else
07052 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07053 #endif
07054 make_file(fn, sizeof(fn), todir, msgnum);
07055 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07056
07057 if (!ast_strlen_zero(vmu->attachfmt)) {
07058 if (strstr(fmt, vmu->attachfmt))
07059 fmt = vmu->attachfmt;
07060 else
07061 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);
07062 }
07063
07064
07065 fmt = ast_strdupa(fmt);
07066 stringp = fmt;
07067 strsep(&stringp, "|");
07068
07069 if (!ast_strlen_zero(vmu->serveremail))
07070 myserveremail = vmu->serveremail;
07071
07072 if (!ast_strlen_zero(vmu->email)) {
07073 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07074
07075 if (attach_user_voicemail)
07076 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07077
07078
07079 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07080
07081 if (attach_user_voicemail)
07082 DISPOSE(todir, msgnum);
07083 }
07084
07085 if (!ast_strlen_zero(vmu->pager)) {
07086 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07087 }
07088
07089 if (ast_test_flag(vmu, VM_DELETE))
07090 DELETE(todir, msgnum, fn, vmu);
07091
07092
07093 if (ast_app_has_voicemail(ext_context, NULL))
07094 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07095
07096 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07097
07098 ast_manager_event(chan, 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);
07099 run_externnotify(vmu->context, vmu->mailbox, flag);
07100
07101 #ifdef IMAP_STORAGE
07102 vm_delete(fn);
07103 if (ast_test_flag(vmu, VM_DELETE)) {
07104 vm_imap_delete(NULL, vms->curmsg, vmu);
07105 vms->newmessages--;
07106 }
07107 #endif
07108
07109 return 0;
07110 }
07111
07112
07113
07114
07115
07116
07117
07118
07119
07120
07121
07122
07123
07124
07125
07126
07127
07128
07129
07130
07131
07132
07133
07134
07135
07136
07137
07138
07139 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)
07140 {
07141 #ifdef IMAP_STORAGE
07142 int todircount = 0;
07143 struct vm_state *dstvms;
07144 #endif
07145 char username[70]="";
07146 char fn[PATH_MAX];
07147 char ecodes[16] = "#";
07148 int res = 0, cmd = 0;
07149 struct ast_vm_user *receiver = NULL, *vmtmp;
07150 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07151 char *stringp;
07152 const char *s;
07153 int saved_messages = 0;
07154 int valid_extensions = 0;
07155 char *dir;
07156 int curmsg;
07157 char urgent_str[7] = "";
07158 int prompt_played = 0;
07159 #ifndef IMAP_STORAGE
07160 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07161 #endif
07162 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07163 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07164 }
07165
07166 if (vms == NULL) return -1;
07167 dir = vms->curdir;
07168 curmsg = vms->curmsg;
07169
07170 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07171 while (!res && !valid_extensions) {
07172 int use_directory = 0;
07173 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07174 int done = 0;
07175 int retries = 0;
07176 cmd = 0;
07177 while ((cmd >= 0) && !done ){
07178 if (cmd)
07179 retries = 0;
07180 switch (cmd) {
07181 case '1':
07182 use_directory = 0;
07183 done = 1;
07184 break;
07185 case '2':
07186 use_directory = 1;
07187 done = 1;
07188 break;
07189 case '*':
07190 cmd = 't';
07191 done = 1;
07192 break;
07193 default:
07194
07195 cmd = ast_play_and_wait(chan, "vm-forward");
07196 if (!cmd) {
07197 cmd = ast_waitfordigit(chan, 3000);
07198 }
07199 if (!cmd) {
07200 retries++;
07201 }
07202 if (retries > 3) {
07203 cmd = 't';
07204 done = 1;
07205 }
07206 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07207 }
07208 }
07209 if (cmd < 0 || cmd == 't')
07210 break;
07211 }
07212
07213 if (use_directory) {
07214
07215
07216 char old_context[sizeof(chan->context)];
07217 char old_exten[sizeof(chan->exten)];
07218 int old_priority;
07219 struct ast_app* directory_app;
07220
07221 directory_app = pbx_findapp("Directory");
07222 if (directory_app) {
07223 char vmcontext[256];
07224
07225 memcpy(old_context, chan->context, sizeof(chan->context));
07226 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07227 old_priority = chan->priority;
07228
07229
07230 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07231 res = pbx_exec(chan, directory_app, vmcontext);
07232
07233 ast_copy_string(username, chan->exten, sizeof(username));
07234
07235
07236 memcpy(chan->context, old_context, sizeof(chan->context));
07237 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07238 chan->priority = old_priority;
07239 } else {
07240 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07241 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07242 }
07243 } else {
07244
07245 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07246 res = ast_streamfile(chan, "vm-extension", chan->language);
07247 prompt_played++;
07248 if (res || prompt_played > 4)
07249 break;
07250 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07251 break;
07252 }
07253
07254
07255 if (ast_strlen_zero(username))
07256 continue;
07257 stringp = username;
07258 s = strsep(&stringp, "*");
07259
07260 valid_extensions = 1;
07261 while (s) {
07262 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07263 int oldmsgs;
07264 int newmsgs;
07265 int capacity;
07266 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07267 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07268
07269 res = ast_play_and_wait(chan, "pbx-invalid");
07270 valid_extensions = 0;
07271 break;
07272 }
07273 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07274 if ((newmsgs + oldmsgs) >= capacity) {
07275 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07276 res = ast_play_and_wait(chan, "vm-mailboxfull");
07277 valid_extensions = 0;
07278 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07279 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07280 free_user(vmtmp);
07281 }
07282 inprocess_count(receiver->mailbox, receiver->context, -1);
07283 break;
07284 }
07285 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07286 } else {
07287
07288
07289
07290
07291
07292 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07293 free_user(receiver);
07294 }
07295 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07296
07297 res = ast_play_and_wait(chan, "pbx-invalid");
07298 valid_extensions = 0;
07299 break;
07300 }
07301
07302
07303 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07304 RETRIEVE(fn, -1, s, receiver->context);
07305 if (ast_fileexists(fn, NULL, NULL) > 0) {
07306 res = ast_stream_and_wait(chan, fn, ecodes);
07307 if (res) {
07308 DISPOSE(fn, -1);
07309 return res;
07310 }
07311 } else {
07312 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07313 }
07314 DISPOSE(fn, -1);
07315
07316 s = strsep(&stringp, "*");
07317 }
07318
07319 if (valid_extensions)
07320 break;
07321 }
07322
07323 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07324 return res;
07325 if (is_new_message == 1) {
07326 struct leave_vm_options leave_options;
07327 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07328 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07329
07330
07331 memset(&leave_options, 0, sizeof(leave_options));
07332 leave_options.record_gain = record_gain;
07333 cmd = leave_voicemail(chan, mailbox, &leave_options);
07334 } else {
07335
07336 long duration = 0;
07337 struct vm_state vmstmp;
07338 int copy_msg_result = 0;
07339 memcpy(&vmstmp, vms, sizeof(vmstmp));
07340
07341 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07342
07343 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07344 if (!cmd) {
07345 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07346 #ifdef IMAP_STORAGE
07347 int attach_user_voicemail;
07348 char *myserveremail = serveremail;
07349
07350
07351 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07352 if (!dstvms) {
07353 dstvms = create_vm_state_from_user(vmtmp);
07354 }
07355 if (dstvms) {
07356 init_mailstream(dstvms, 0);
07357 if (!dstvms->mailstream) {
07358 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07359 } else {
07360 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07361 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07362 }
07363 } else {
07364 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07365 }
07366 if (!ast_strlen_zero(vmtmp->serveremail))
07367 myserveremail = vmtmp->serveremail;
07368 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07369
07370 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07371 dstvms->curbox,
07372 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07373 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07374 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07375 NULL, urgent_str);
07376 #else
07377 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07378 #endif
07379 saved_messages++;
07380 AST_LIST_REMOVE_CURRENT(list);
07381 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07382 free_user(vmtmp);
07383 if (res)
07384 break;
07385 }
07386 AST_LIST_TRAVERSE_SAFE_END;
07387 if (saved_messages > 0 && !copy_msg_result) {
07388
07389
07390
07391
07392
07393
07394
07395
07396 #ifdef IMAP_STORAGE
07397
07398 if (ast_strlen_zero(vmstmp.introfn))
07399 #endif
07400 res = ast_play_and_wait(chan, "vm-msgsaved");
07401 }
07402 #ifndef IMAP_STORAGE
07403 else {
07404
07405 res = ast_play_and_wait(chan, "vm-mailboxfull");
07406 }
07407
07408 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07409 strcpy(textfile, msgfile);
07410 strcpy(backup, msgfile);
07411 strcpy(backup_textfile, msgfile);
07412 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07413 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07414 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07415 if (ast_fileexists(backup, NULL, NULL) > 0) {
07416 ast_filerename(backup, msgfile, NULL);
07417 rename(backup_textfile, textfile);
07418 }
07419 #endif
07420 }
07421 DISPOSE(dir, curmsg);
07422 #ifndef IMAP_STORAGE
07423 if (cmd) {
07424 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07425 strcpy(textfile, msgfile);
07426 strcpy(backup_textfile, msgfile);
07427 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07428 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07429 rename(backup_textfile, textfile);
07430 }
07431 #endif
07432 }
07433
07434
07435 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07436 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07437 free_user(vmtmp);
07438 }
07439 return res ? res : cmd;
07440 }
07441
07442 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07443 {
07444 int res;
07445 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07446 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07447 return res;
07448 }
07449
07450 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07451 {
07452 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07453 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);
07454 }
07455
07456 static int play_message_category(struct ast_channel *chan, const char *category)
07457 {
07458 int res = 0;
07459
07460 if (!ast_strlen_zero(category))
07461 res = ast_play_and_wait(chan, category);
07462
07463 if (res) {
07464 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07465 res = 0;
07466 }
07467
07468 return res;
07469 }
07470
07471 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07472 {
07473 int res = 0;
07474 struct vm_zone *the_zone = NULL;
07475 time_t t;
07476
07477 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07478 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07479 return 0;
07480 }
07481
07482
07483 if (!ast_strlen_zero(vmu->zonetag)) {
07484
07485 struct vm_zone *z;
07486 AST_LIST_LOCK(&zones);
07487 AST_LIST_TRAVERSE(&zones, z, list) {
07488 if (!strcmp(z->name, vmu->zonetag)) {
07489 the_zone = z;
07490 break;
07491 }
07492 }
07493 AST_LIST_UNLOCK(&zones);
07494 }
07495
07496
07497 #if 0
07498
07499 ast_localtime(&t, &time_now, NULL);
07500 tv_now = ast_tvnow();
07501 ast_localtime(&tv_now, &time_then, NULL);
07502
07503
07504 if (time_now.tm_year == time_then.tm_year)
07505 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07506 else
07507 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07508 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07509
07510
07511 #endif
07512 if (the_zone) {
07513 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07514 } else if (!strncasecmp(chan->language, "de", 2)) {
07515 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07516 } else if (!strncasecmp(chan->language, "gr", 2)) {
07517 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07518 } else if (!strncasecmp(chan->language, "it", 2)) {
07519 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);
07520 } else if (!strncasecmp(chan->language, "nl", 2)) {
07521 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07522 } else if (!strncasecmp(chan->language, "no", 2)) {
07523 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07524 } else if (!strncasecmp(chan->language, "pl", 2)) {
07525 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07526 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07527 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);
07528 } else if (!strncasecmp(chan->language, "se", 2)) {
07529 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07530 } else if (!strncasecmp(chan->language, "zh", 2)) {
07531 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07532 } else if (!strncasecmp(chan->language, "vi", 2)) {
07533 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' A 'digits/day' dB 'digits/year' Y 'digits/at' k 'hours' M 'minutes'", NULL);
07534 } else {
07535 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07536 }
07537 #if 0
07538 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07539 #endif
07540 return res;
07541 }
07542
07543
07544
07545 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07546 {
07547 int res = 0;
07548 int i;
07549 char *callerid, *name;
07550 char prefile[PATH_MAX] = "";
07551
07552
07553
07554
07555
07556
07557
07558
07559
07560 if ((cid == NULL)||(context == NULL))
07561 return res;
07562
07563
07564 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07565 ast_callerid_parse(cid, &name, &callerid);
07566 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07567
07568
07569 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07570 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07571 if ((strcmp(cidinternalcontexts[i], context) == 0))
07572 break;
07573 }
07574 if (i != MAX_NUM_CID_CONTEXTS){
07575 if (!res) {
07576 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07577 if (!ast_strlen_zero(prefile)) {
07578
07579 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07580 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07581 if (!callback)
07582 res = wait_file2(chan, vms, "vm-from");
07583 res = ast_stream_and_wait(chan, prefile, "");
07584 } else {
07585 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07586
07587 if (!callback)
07588 res = wait_file2(chan, vms, "vm-from-extension");
07589 res = ast_say_digit_str(chan, callerid, "", chan->language);
07590 }
07591 }
07592 }
07593 } else if (!res) {
07594 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07595
07596 if (!callback)
07597 res = wait_file2(chan, vms, "vm-from-phonenumber");
07598 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07599 }
07600 } else {
07601
07602 ast_debug(1, "VM-CID: From an unknown number\n");
07603
07604 res = wait_file2(chan, vms, "vm-unknown-caller");
07605 }
07606 return res;
07607 }
07608
07609 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07610 {
07611 int res = 0;
07612 int durationm;
07613 int durations;
07614
07615 if (duration == NULL)
07616 return res;
07617
07618
07619 durations = atoi(duration);
07620 durationm = (durations / 60);
07621
07622 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07623
07624 if ((!res) && (durationm >= minduration)) {
07625 res = wait_file2(chan, vms, "vm-duration");
07626
07627
07628 if (!strncasecmp(chan->language, "pl", 2)) {
07629 div_t num = div(durationm, 10);
07630
07631 if (durationm == 1) {
07632 res = ast_play_and_wait(chan, "digits/1z");
07633 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07634 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07635 if (num.rem == 2) {
07636 if (!num.quot) {
07637 res = ast_play_and_wait(chan, "digits/2-ie");
07638 } else {
07639 res = say_and_wait(chan, durationm - 2 , chan->language);
07640 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07641 }
07642 } else {
07643 res = say_and_wait(chan, durationm, chan->language);
07644 }
07645 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07646 } else {
07647 res = say_and_wait(chan, durationm, chan->language);
07648 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07649 }
07650
07651 } else {
07652 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07653 res = wait_file2(chan, vms, "vm-minutes");
07654 }
07655 }
07656 return res;
07657 }
07658
07659 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07660 {
07661 int res = 0;
07662 char filename[256], *cid;
07663 const char *origtime, *context, *category, *duration, *flag;
07664 struct ast_config *msg_cfg;
07665 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07666
07667 vms->starting = 0;
07668 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07669 adsi_message(chan, vms);
07670 if (!vms->curmsg) {
07671 res = wait_file2(chan, vms, "vm-first");
07672 } else if (vms->curmsg == vms->lastmsg) {
07673 res = wait_file2(chan, vms, "vm-last");
07674 }
07675
07676 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07677 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07678 msg_cfg = ast_config_load(filename, config_flags);
07679 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07680 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07681 return 0;
07682 }
07683 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07684
07685
07686 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07687 res = wait_file2(chan, vms, "vm-Urgent");
07688 }
07689
07690 if (!res) {
07691
07692
07693 if (!strncasecmp(chan->language, "pl", 2)) {
07694 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07695 int ten, one;
07696 char nextmsg[256];
07697 ten = (vms->curmsg + 1) / 10;
07698 one = (vms->curmsg + 1) % 10;
07699
07700 if (vms->curmsg < 20) {
07701 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07702 res = wait_file2(chan, vms, nextmsg);
07703 } else {
07704 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07705 res = wait_file2(chan, vms, nextmsg);
07706 if (one > 0) {
07707 if (!res) {
07708 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07709 res = wait_file2(chan, vms, nextmsg);
07710 }
07711 }
07712 }
07713 }
07714 if (!res)
07715 res = wait_file2(chan, vms, "vm-message");
07716
07717 } else if (!strncasecmp(chan->language, "he", 2)) {
07718 if (!vms->curmsg) {
07719 res = wait_file2(chan, vms, "vm-message");
07720 res = wait_file2(chan, vms, "vm-first");
07721 } else if (vms->curmsg == vms->lastmsg) {
07722 res = wait_file2(chan, vms, "vm-message");
07723 res = wait_file2(chan, vms, "vm-last");
07724 } else {
07725 res = wait_file2(chan, vms, "vm-message");
07726 res = wait_file2(chan, vms, "vm-number");
07727 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07728 }
07729
07730 } else if (!strncasecmp(chan->language, "vi", 2)) {
07731 if (!vms->curmsg) {
07732 res = wait_file2(chan, vms, "vm-message");
07733 res = wait_file2(chan, vms, "vm-first");
07734 } else if (vms->curmsg == vms->lastmsg) {
07735 res = wait_file2(chan, vms, "vm-message");
07736 res = wait_file2(chan, vms, "vm-last");
07737 } else {
07738 res = wait_file2(chan, vms, "vm-message");
07739 res = wait_file2(chan, vms, "vm-number");
07740 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07741 }
07742 } else {
07743 if (!strncasecmp(chan->language, "se", 2)) {
07744 res = wait_file2(chan, vms, "vm-meddelandet");
07745 } else {
07746 res = wait_file2(chan, vms, "vm-message");
07747 }
07748 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07749 if (!res) {
07750 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07751 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07752 }
07753 }
07754 }
07755 }
07756
07757 if (!msg_cfg) {
07758 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07759 return 0;
07760 }
07761
07762 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07763 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07764 DISPOSE(vms->curdir, vms->curmsg);
07765 ast_config_destroy(msg_cfg);
07766 return 0;
07767 }
07768
07769 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07770 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07771 category = ast_variable_retrieve(msg_cfg, "message", "category");
07772
07773 context = ast_variable_retrieve(msg_cfg, "message", "context");
07774 if (!strncasecmp("macro", context, 5))
07775 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07776 if (!res) {
07777 res = play_message_category(chan, category);
07778 }
07779 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07780 res = play_message_datetime(chan, vmu, origtime, filename);
07781 }
07782 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07783 res = play_message_callerid(chan, vms, cid, context, 0);
07784 }
07785 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07786 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07787 }
07788
07789 if (res == '1') {
07790 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07791 res = 0;
07792 }
07793 ast_config_destroy(msg_cfg);
07794
07795 if (!res) {
07796 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07797 #ifdef IMAP_STORAGE
07798 ast_mutex_lock(&vms->lock);
07799 #endif
07800 vms->heard[vms->curmsg] = 1;
07801 #ifdef IMAP_STORAGE
07802 ast_mutex_unlock(&vms->lock);
07803
07804
07805
07806 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07807 wait_file(chan, vms, vms->introfn);
07808 }
07809 #endif
07810 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07811 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07812 res = 0;
07813 }
07814 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07815 }
07816 DISPOSE(vms->curdir, vms->curmsg);
07817 return res;
07818 }
07819
07820 #ifdef IMAP_STORAGE
07821 static int imap_remove_file(char *dir, int msgnum)
07822 {
07823 char fn[PATH_MAX];
07824 char full_fn[PATH_MAX];
07825 char intro[PATH_MAX] = {0,};
07826
07827 if (msgnum > -1) {
07828 make_file(fn, sizeof(fn), dir, msgnum);
07829 snprintf(intro, sizeof(intro), "%sintro", fn);
07830 } else
07831 ast_copy_string(fn, dir, sizeof(fn));
07832
07833 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07834 ast_filedelete(fn, NULL);
07835 if (!ast_strlen_zero(intro)) {
07836 ast_filedelete(intro, NULL);
07837 }
07838 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07839 unlink(full_fn);
07840 }
07841 return 0;
07842 }
07843
07844
07845
07846 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07847 {
07848 char *file, *filename;
07849 char *attachment;
07850 char arg[10];
07851 int i;
07852 BODY* body;
07853
07854 file = strrchr(ast_strdupa(dir), '/');
07855 if (file) {
07856 *file++ = '\0';
07857 } else {
07858 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07859 return -1;
07860 }
07861
07862 ast_mutex_lock(&vms->lock);
07863 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07864 mail_fetchstructure(vms->mailstream, i + 1, &body);
07865
07866 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07867 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07868 } else {
07869 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07870 ast_mutex_unlock(&vms->lock);
07871 return -1;
07872 }
07873 filename = strsep(&attachment, ".");
07874 if (!strcmp(filename, file)) {
07875 sprintf(arg, "%d", i + 1);
07876 mail_setflag(vms->mailstream, arg, "\\DELETED");
07877 }
07878 }
07879 mail_expunge(vms->mailstream);
07880 ast_mutex_unlock(&vms->lock);
07881 return 0;
07882 }
07883
07884 #elif !defined(IMAP_STORAGE)
07885 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07886 {
07887 int count_msg, last_msg;
07888
07889 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07890
07891
07892
07893
07894 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07895
07896
07897 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07898
07899
07900 count_msg = count_messages(vmu, vms->curdir);
07901 if (count_msg < 0) {
07902 return count_msg;
07903 } else {
07904 vms->lastmsg = count_msg - 1;
07905 }
07906
07907 if (vm_allocate_dh(vms, vmu, count_msg)) {
07908 return -1;
07909 }
07910
07911
07912
07913
07914
07915
07916
07917
07918 if (vm_lock_path(vms->curdir)) {
07919 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07920 return ERROR_LOCK_PATH;
07921 }
07922
07923
07924 last_msg = last_message_index(vmu, vms->curdir);
07925 ast_unlock_path(vms->curdir);
07926
07927 if (last_msg < -1) {
07928 return last_msg;
07929 } else if (vms->lastmsg != last_msg) {
07930 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);
07931 resequence_mailbox(vmu, vms->curdir, count_msg);
07932 }
07933
07934 return 0;
07935 }
07936 #endif
07937
07938 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07939 {
07940 int x = 0;
07941 int last_msg_idx = 0;
07942
07943 #ifndef IMAP_STORAGE
07944 int res = 0, nummsg;
07945 char fn2[PATH_MAX];
07946 #endif
07947
07948 if (vms->lastmsg <= -1) {
07949 goto done;
07950 }
07951
07952 vms->curmsg = -1;
07953 #ifndef IMAP_STORAGE
07954
07955 if (vm_lock_path(vms->curdir)) {
07956 return ERROR_LOCK_PATH;
07957 }
07958
07959
07960 last_msg_idx = last_message_index(vmu, vms->curdir);
07961 if (last_msg_idx != vms->lastmsg) {
07962 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
07963 }
07964
07965
07966 for (x = 0; x < last_msg_idx + 1; x++) {
07967 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07968
07969 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07970 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07971 break;
07972 }
07973 vms->curmsg++;
07974 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07975 if (strcmp(vms->fn, fn2)) {
07976 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07977 }
07978 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07979
07980 res = save_to_folder(vmu, vms, x, 1);
07981 if (res == ERROR_LOCK_PATH) {
07982
07983 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07984 vms->deleted[x] = 0;
07985 vms->heard[x] = 0;
07986 --x;
07987 }
07988 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07989
07990 res = save_to_folder(vmu, vms, x, 10);
07991 if (res == ERROR_LOCK_PATH) {
07992
07993 vms->deleted[x] = 0;
07994 vms->heard[x] = 0;
07995 --x;
07996 }
07997 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07998
07999
08000 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08001 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08002 DELETE(vms->curdir, x, vms->fn, vmu);
08003 }
08004 }
08005 }
08006
08007
08008 nummsg = x - 1;
08009 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08010 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08011 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08012 DELETE(vms->curdir, x, vms->fn, vmu);
08013 }
08014 }
08015 ast_unlock_path(vms->curdir);
08016 #else
08017 ast_mutex_lock(&vms->lock);
08018 if (vms->deleted) {
08019
08020
08021 last_msg_idx = vms->dh_arraysize;
08022 for (x = last_msg_idx - 1; x >= 0; x--) {
08023 if (vms->deleted[x]) {
08024 ast_debug(3, "IMAP delete of %d\n", x);
08025 DELETE(vms->curdir, x, vms->fn, vmu);
08026 }
08027 }
08028 }
08029 #endif
08030
08031 done:
08032 if (vms->deleted) {
08033 ast_free(vms->deleted);
08034 vms->deleted = NULL;
08035 }
08036 if (vms->heard) {
08037 ast_free(vms->heard);
08038 vms->heard = NULL;
08039 }
08040 vms->dh_arraysize = 0;
08041 #ifdef IMAP_STORAGE
08042 ast_mutex_unlock(&vms->lock);
08043 #endif
08044
08045 return 0;
08046 }
08047
08048
08049
08050
08051
08052
08053
08054 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08055 {
08056 int cmd;
08057 char *buf;
08058
08059 buf = alloca(strlen(box) + 2);
08060 strcpy(buf, box);
08061 strcat(buf, "s");
08062
08063 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08064 cmd = ast_play_and_wait(chan, buf);
08065 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08066 } else {
08067 cmd = ast_play_and_wait(chan, "vm-messages");
08068 return cmd ? cmd : ast_play_and_wait(chan, box);
08069 }
08070 }
08071
08072 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08073 {
08074 int cmd;
08075
08076 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08077 if (!strcasecmp(box, "vm-INBOX"))
08078 cmd = ast_play_and_wait(chan, "vm-new-e");
08079 else
08080 cmd = ast_play_and_wait(chan, "vm-old-e");
08081 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08082 } else {
08083 cmd = ast_play_and_wait(chan, "vm-messages");
08084 return cmd ? cmd : ast_play_and_wait(chan, box);
08085 }
08086 }
08087
08088 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08089 {
08090 int cmd;
08091
08092 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08093 cmd = ast_play_and_wait(chan, "vm-messages");
08094 return cmd ? cmd : ast_play_and_wait(chan, box);
08095 } else {
08096 cmd = ast_play_and_wait(chan, box);
08097 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08098 }
08099 }
08100
08101 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08102 {
08103 int cmd;
08104
08105 if ( !strncasecmp(chan->language, "it", 2) ||
08106 !strncasecmp(chan->language, "es", 2) ||
08107 !strncasecmp(chan->language, "pt", 2)) {
08108 cmd = ast_play_and_wait(chan, "vm-messages");
08109 return cmd ? cmd : ast_play_and_wait(chan, box);
08110 } else if (!strncasecmp(chan->language, "gr", 2)) {
08111 return vm_play_folder_name_gr(chan, box);
08112 } else if (!strncasecmp(chan->language, "he", 2)) {
08113 return ast_play_and_wait(chan, box);
08114 } else if (!strncasecmp(chan->language, "pl", 2)) {
08115 return vm_play_folder_name_pl(chan, box);
08116 } else if (!strncasecmp(chan->language, "ua", 2)) {
08117 return vm_play_folder_name_ua(chan, box);
08118 } else if (!strncasecmp(chan->language, "vi", 2)) {
08119 return ast_play_and_wait(chan, box);
08120 } else {
08121 cmd = ast_play_and_wait(chan, box);
08122 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08123 }
08124 }
08125
08126
08127
08128
08129
08130
08131
08132
08133
08134
08135
08136
08137
08138 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08139 {
08140 int res = 0;
08141
08142 if (vms->newmessages) {
08143 res = ast_play_and_wait(chan, "vm-youhave");
08144 if (!res)
08145 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08146 if (!res) {
08147 if ((vms->newmessages == 1)) {
08148 res = ast_play_and_wait(chan, "vm-INBOX");
08149 if (!res)
08150 res = ast_play_and_wait(chan, "vm-message");
08151 } else {
08152 res = ast_play_and_wait(chan, "vm-INBOXs");
08153 if (!res)
08154 res = ast_play_and_wait(chan, "vm-messages");
08155 }
08156 }
08157 } else if (vms->oldmessages){
08158 res = ast_play_and_wait(chan, "vm-youhave");
08159 if (!res)
08160 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08161 if ((vms->oldmessages == 1)){
08162 res = ast_play_and_wait(chan, "vm-Old");
08163 if (!res)
08164 res = ast_play_and_wait(chan, "vm-message");
08165 } else {
08166 res = ast_play_and_wait(chan, "vm-Olds");
08167 if (!res)
08168 res = ast_play_and_wait(chan, "vm-messages");
08169 }
08170 } else if (!vms->oldmessages && !vms->newmessages)
08171 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08172 return res;
08173 }
08174
08175
08176
08177
08178
08179
08180
08181
08182
08183
08184
08185
08186
08187
08188
08189
08190
08191
08192
08193
08194
08195
08196
08197
08198
08199
08200
08201
08202
08203
08204
08205
08206
08207
08208
08209
08210
08211
08212
08213
08214
08215
08216
08217
08218
08219
08220
08221
08222
08223
08224
08225
08226
08227
08228
08229
08230
08231
08232 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08233 {
08234 int res;
08235 int lastnum = 0;
08236
08237 res = ast_play_and_wait(chan, "vm-youhave");
08238
08239 if (!res && vms->newmessages) {
08240 lastnum = vms->newmessages;
08241
08242 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08243 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08244 }
08245
08246 if (!res && vms->oldmessages) {
08247 res = ast_play_and_wait(chan, "vm-and");
08248 }
08249 }
08250
08251 if (!res && vms->oldmessages) {
08252 lastnum = vms->oldmessages;
08253
08254 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08255 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08256 }
08257 }
08258
08259 if (!res) {
08260 if (lastnum == 0) {
08261 res = ast_play_and_wait(chan, "vm-no");
08262 }
08263 if (!res) {
08264 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08265 }
08266 }
08267
08268 return res;
08269 }
08270
08271
08272 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08273 {
08274 int res = 0;
08275
08276
08277 if (!res) {
08278 if ((vms->newmessages) || (vms->oldmessages)) {
08279 res = ast_play_and_wait(chan, "vm-youhave");
08280 }
08281
08282
08283
08284
08285
08286 if (vms->newmessages) {
08287 if (!res) {
08288 if (vms->newmessages == 1) {
08289 res = ast_play_and_wait(chan, "vm-INBOX1");
08290 } else {
08291 if (vms->newmessages == 2) {
08292 res = ast_play_and_wait(chan, "vm-shtei");
08293 } else {
08294 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08295 }
08296 res = ast_play_and_wait(chan, "vm-INBOX");
08297 }
08298 }
08299 if (vms->oldmessages && !res) {
08300 res = ast_play_and_wait(chan, "vm-and");
08301 if (vms->oldmessages == 1) {
08302 res = ast_play_and_wait(chan, "vm-Old1");
08303 } else {
08304 if (vms->oldmessages == 2) {
08305 res = ast_play_and_wait(chan, "vm-shtei");
08306 } else {
08307 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08308 }
08309 res = ast_play_and_wait(chan, "vm-Old");
08310 }
08311 }
08312 }
08313 if (!res && vms->oldmessages && !vms->newmessages) {
08314 if (!res) {
08315 if (vms->oldmessages == 1) {
08316 res = ast_play_and_wait(chan, "vm-Old1");
08317 } else {
08318 if (vms->oldmessages == 2) {
08319 res = ast_play_and_wait(chan, "vm-shtei");
08320 } else {
08321 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08322 }
08323 res = ast_play_and_wait(chan, "vm-Old");
08324 }
08325 }
08326 }
08327 if (!res) {
08328 if (!vms->oldmessages && !vms->newmessages) {
08329 if (!res) {
08330 res = ast_play_and_wait(chan, "vm-nomessages");
08331 }
08332 }
08333 }
08334 }
08335 return res;
08336 }
08337
08338
08339 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08340 {
08341 int res;
08342
08343
08344 res = ast_play_and_wait(chan, "vm-youhave");
08345 if (!res) {
08346 if (vms->urgentmessages) {
08347 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08348 if (!res)
08349 res = ast_play_and_wait(chan, "vm-Urgent");
08350 if ((vms->oldmessages || vms->newmessages) && !res) {
08351 res = ast_play_and_wait(chan, "vm-and");
08352 } else if (!res) {
08353 if ((vms->urgentmessages == 1))
08354 res = ast_play_and_wait(chan, "vm-message");
08355 else
08356 res = ast_play_and_wait(chan, "vm-messages");
08357 }
08358 }
08359 if (vms->newmessages) {
08360 res = say_and_wait(chan, vms->newmessages, chan->language);
08361 if (!res)
08362 res = ast_play_and_wait(chan, "vm-INBOX");
08363 if (vms->oldmessages && !res)
08364 res = ast_play_and_wait(chan, "vm-and");
08365 else if (!res) {
08366 if ((vms->newmessages == 1))
08367 res = ast_play_and_wait(chan, "vm-message");
08368 else
08369 res = ast_play_and_wait(chan, "vm-messages");
08370 }
08371
08372 }
08373 if (!res && vms->oldmessages) {
08374 res = say_and_wait(chan, vms->oldmessages, chan->language);
08375 if (!res)
08376 res = ast_play_and_wait(chan, "vm-Old");
08377 if (!res) {
08378 if (vms->oldmessages == 1)
08379 res = ast_play_and_wait(chan, "vm-message");
08380 else
08381 res = ast_play_and_wait(chan, "vm-messages");
08382 }
08383 }
08384 if (!res) {
08385 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08386 res = ast_play_and_wait(chan, "vm-no");
08387 if (!res)
08388 res = ast_play_and_wait(chan, "vm-messages");
08389 }
08390 }
08391 }
08392 return res;
08393 }
08394
08395
08396 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08397 {
08398
08399 int res;
08400 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08401 res = ast_play_and_wait(chan, "vm-no") ||
08402 ast_play_and_wait(chan, "vm-message");
08403 else
08404 res = ast_play_and_wait(chan, "vm-youhave");
08405 if (!res && vms->newmessages) {
08406 res = (vms->newmessages == 1) ?
08407 ast_play_and_wait(chan, "digits/un") ||
08408 ast_play_and_wait(chan, "vm-nuovo") ||
08409 ast_play_and_wait(chan, "vm-message") :
08410
08411 say_and_wait(chan, vms->newmessages, chan->language) ||
08412 ast_play_and_wait(chan, "vm-nuovi") ||
08413 ast_play_and_wait(chan, "vm-messages");
08414 if (!res && vms->oldmessages)
08415 res = ast_play_and_wait(chan, "vm-and");
08416 }
08417 if (!res && vms->oldmessages) {
08418 res = (vms->oldmessages == 1) ?
08419 ast_play_and_wait(chan, "digits/un") ||
08420 ast_play_and_wait(chan, "vm-vecchio") ||
08421 ast_play_and_wait(chan, "vm-message") :
08422
08423 say_and_wait(chan, vms->oldmessages, chan->language) ||
08424 ast_play_and_wait(chan, "vm-vecchi") ||
08425 ast_play_and_wait(chan, "vm-messages");
08426 }
08427 return res;
08428 }
08429
08430
08431 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08432 {
08433
08434 int res;
08435 div_t num;
08436
08437 if (!vms->oldmessages && !vms->newmessages) {
08438 res = ast_play_and_wait(chan, "vm-no");
08439 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08440 return res;
08441 } else {
08442 res = ast_play_and_wait(chan, "vm-youhave");
08443 }
08444
08445 if (vms->newmessages) {
08446 num = div(vms->newmessages, 10);
08447 if (vms->newmessages == 1) {
08448 res = ast_play_and_wait(chan, "digits/1-a");
08449 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08450 res = res ? res : ast_play_and_wait(chan, "vm-message");
08451 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08452 if (num.rem == 2) {
08453 if (!num.quot) {
08454 res = ast_play_and_wait(chan, "digits/2-ie");
08455 } else {
08456 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08457 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08458 }
08459 } else {
08460 res = say_and_wait(chan, vms->newmessages, chan->language);
08461 }
08462 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08463 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08464 } else {
08465 res = say_and_wait(chan, vms->newmessages, chan->language);
08466 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08467 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08468 }
08469 if (!res && vms->oldmessages)
08470 res = ast_play_and_wait(chan, "vm-and");
08471 }
08472 if (!res && vms->oldmessages) {
08473 num = div(vms->oldmessages, 10);
08474 if (vms->oldmessages == 1) {
08475 res = ast_play_and_wait(chan, "digits/1-a");
08476 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08477 res = res ? res : ast_play_and_wait(chan, "vm-message");
08478 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08479 if (num.rem == 2) {
08480 if (!num.quot) {
08481 res = ast_play_and_wait(chan, "digits/2-ie");
08482 } else {
08483 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08484 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08485 }
08486 } else {
08487 res = say_and_wait(chan, vms->oldmessages, chan->language);
08488 }
08489 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08490 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08491 } else {
08492 res = say_and_wait(chan, vms->oldmessages, chan->language);
08493 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08494 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08495 }
08496 }
08497
08498 return res;
08499 }
08500
08501
08502 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08503 {
08504
08505 int res;
08506
08507 res = ast_play_and_wait(chan, "vm-youhave");
08508 if (res)
08509 return res;
08510
08511 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08512 res = ast_play_and_wait(chan, "vm-no");
08513 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08514 return res;
08515 }
08516
08517 if (vms->newmessages) {
08518 if ((vms->newmessages == 1)) {
08519 res = ast_play_and_wait(chan, "digits/ett");
08520 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08521 res = res ? res : ast_play_and_wait(chan, "vm-message");
08522 } else {
08523 res = say_and_wait(chan, vms->newmessages, chan->language);
08524 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08525 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08526 }
08527 if (!res && vms->oldmessages)
08528 res = ast_play_and_wait(chan, "vm-and");
08529 }
08530 if (!res && vms->oldmessages) {
08531 if (vms->oldmessages == 1) {
08532 res = ast_play_and_wait(chan, "digits/ett");
08533 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08534 res = res ? res : ast_play_and_wait(chan, "vm-message");
08535 } else {
08536 res = say_and_wait(chan, vms->oldmessages, chan->language);
08537 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08538 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08539 }
08540 }
08541
08542 return res;
08543 }
08544
08545
08546 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08547 {
08548
08549 int res;
08550
08551 res = ast_play_and_wait(chan, "vm-youhave");
08552 if (res)
08553 return res;
08554
08555 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08556 res = ast_play_and_wait(chan, "vm-no");
08557 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08558 return res;
08559 }
08560
08561 if (vms->newmessages) {
08562 if ((vms->newmessages == 1)) {
08563 res = ast_play_and_wait(chan, "digits/1");
08564 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08565 res = res ? res : ast_play_and_wait(chan, "vm-message");
08566 } else {
08567 res = say_and_wait(chan, vms->newmessages, chan->language);
08568 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08569 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08570 }
08571 if (!res && vms->oldmessages)
08572 res = ast_play_and_wait(chan, "vm-and");
08573 }
08574 if (!res && vms->oldmessages) {
08575 if (vms->oldmessages == 1) {
08576 res = ast_play_and_wait(chan, "digits/1");
08577 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08578 res = res ? res : ast_play_and_wait(chan, "vm-message");
08579 } else {
08580 res = say_and_wait(chan, vms->oldmessages, chan->language);
08581 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08582 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08583 }
08584 }
08585
08586 return res;
08587 }
08588
08589
08590 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08591 {
08592
08593 int res;
08594 res = ast_play_and_wait(chan, "vm-youhave");
08595 if (!res) {
08596 if (vms->newmessages) {
08597 if ((vms->newmessages == 1))
08598 res = ast_play_and_wait(chan, "digits/1F");
08599 else
08600 res = say_and_wait(chan, vms->newmessages, chan->language);
08601 if (!res)
08602 res = ast_play_and_wait(chan, "vm-INBOX");
08603 if (vms->oldmessages && !res)
08604 res = ast_play_and_wait(chan, "vm-and");
08605 else if (!res) {
08606 if ((vms->newmessages == 1))
08607 res = ast_play_and_wait(chan, "vm-message");
08608 else
08609 res = ast_play_and_wait(chan, "vm-messages");
08610 }
08611
08612 }
08613 if (!res && vms->oldmessages) {
08614 if (vms->oldmessages == 1)
08615 res = ast_play_and_wait(chan, "digits/1F");
08616 else
08617 res = say_and_wait(chan, vms->oldmessages, chan->language);
08618 if (!res)
08619 res = ast_play_and_wait(chan, "vm-Old");
08620 if (!res) {
08621 if (vms->oldmessages == 1)
08622 res = ast_play_and_wait(chan, "vm-message");
08623 else
08624 res = ast_play_and_wait(chan, "vm-messages");
08625 }
08626 }
08627 if (!res) {
08628 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08629 res = ast_play_and_wait(chan, "vm-no");
08630 if (!res)
08631 res = ast_play_and_wait(chan, "vm-messages");
08632 }
08633 }
08634 }
08635 return res;
08636 }
08637
08638
08639 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08640 {
08641
08642 int res;
08643 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08644 res = ast_play_and_wait(chan, "vm-youhaveno");
08645 if (!res)
08646 res = ast_play_and_wait(chan, "vm-messages");
08647 } else {
08648 res = ast_play_and_wait(chan, "vm-youhave");
08649 }
08650 if (!res) {
08651 if (vms->newmessages) {
08652 if (!res) {
08653 if ((vms->newmessages == 1)) {
08654 res = ast_play_and_wait(chan, "digits/1M");
08655 if (!res)
08656 res = ast_play_and_wait(chan, "vm-message");
08657 if (!res)
08658 res = ast_play_and_wait(chan, "vm-INBOXs");
08659 } else {
08660 res = say_and_wait(chan, vms->newmessages, chan->language);
08661 if (!res)
08662 res = ast_play_and_wait(chan, "vm-messages");
08663 if (!res)
08664 res = ast_play_and_wait(chan, "vm-INBOX");
08665 }
08666 }
08667 if (vms->oldmessages && !res)
08668 res = ast_play_and_wait(chan, "vm-and");
08669 }
08670 if (vms->oldmessages) {
08671 if (!res) {
08672 if (vms->oldmessages == 1) {
08673 res = ast_play_and_wait(chan, "digits/1M");
08674 if (!res)
08675 res = ast_play_and_wait(chan, "vm-message");
08676 if (!res)
08677 res = ast_play_and_wait(chan, "vm-Olds");
08678 } else {
08679 res = say_and_wait(chan, vms->oldmessages, chan->language);
08680 if (!res)
08681 res = ast_play_and_wait(chan, "vm-messages");
08682 if (!res)
08683 res = ast_play_and_wait(chan, "vm-Old");
08684 }
08685 }
08686 }
08687 }
08688 return res;
08689 }
08690
08691
08692 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08693
08694 int res;
08695 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08696 res = ast_play_and_wait(chan, "vm-nomessages");
08697 return res;
08698 } else {
08699 res = ast_play_and_wait(chan, "vm-youhave");
08700 }
08701 if (vms->newmessages) {
08702 if (!res)
08703 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08704 if ((vms->newmessages == 1)) {
08705 if (!res)
08706 res = ast_play_and_wait(chan, "vm-message");
08707 if (!res)
08708 res = ast_play_and_wait(chan, "vm-INBOXs");
08709 } else {
08710 if (!res)
08711 res = ast_play_and_wait(chan, "vm-messages");
08712 if (!res)
08713 res = ast_play_and_wait(chan, "vm-INBOX");
08714 }
08715 if (vms->oldmessages && !res)
08716 res = ast_play_and_wait(chan, "vm-and");
08717 }
08718 if (vms->oldmessages) {
08719 if (!res)
08720 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08721 if (vms->oldmessages == 1) {
08722 if (!res)
08723 res = ast_play_and_wait(chan, "vm-message");
08724 if (!res)
08725 res = ast_play_and_wait(chan, "vm-Olds");
08726 } else {
08727 if (!res)
08728 res = ast_play_and_wait(chan, "vm-messages");
08729 if (!res)
08730 res = ast_play_and_wait(chan, "vm-Old");
08731 }
08732 }
08733 return res;
08734 }
08735
08736
08737 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08738 {
08739
08740 int res;
08741 res = ast_play_and_wait(chan, "vm-youhave");
08742 if (!res) {
08743 if (vms->newmessages) {
08744 res = say_and_wait(chan, vms->newmessages, chan->language);
08745 if (!res)
08746 res = ast_play_and_wait(chan, "vm-INBOX");
08747 if (vms->oldmessages && !res)
08748 res = ast_play_and_wait(chan, "vm-and");
08749 else if (!res) {
08750 if ((vms->newmessages == 1))
08751 res = ast_play_and_wait(chan, "vm-message");
08752 else
08753 res = ast_play_and_wait(chan, "vm-messages");
08754 }
08755
08756 }
08757 if (!res && vms->oldmessages) {
08758 res = say_and_wait(chan, vms->oldmessages, chan->language);
08759 if (!res)
08760 res = ast_play_and_wait(chan, "vm-Old");
08761 if (!res) {
08762 if (vms->oldmessages == 1)
08763 res = ast_play_and_wait(chan, "vm-message");
08764 else
08765 res = ast_play_and_wait(chan, "vm-messages");
08766 }
08767 }
08768 if (!res) {
08769 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08770 res = ast_play_and_wait(chan, "vm-no");
08771 if (!res)
08772 res = ast_play_and_wait(chan, "vm-messages");
08773 }
08774 }
08775 }
08776 return res;
08777 }
08778
08779
08780 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08781 {
08782
08783 int res;
08784 res = ast_play_and_wait(chan, "vm-youhave");
08785 if (!res) {
08786 if (vms->newmessages) {
08787 res = say_and_wait(chan, vms->newmessages, chan->language);
08788 if (!res) {
08789 if (vms->newmessages == 1)
08790 res = ast_play_and_wait(chan, "vm-INBOXs");
08791 else
08792 res = ast_play_and_wait(chan, "vm-INBOX");
08793 }
08794 if (vms->oldmessages && !res)
08795 res = ast_play_and_wait(chan, "vm-and");
08796 else if (!res) {
08797 if ((vms->newmessages == 1))
08798 res = ast_play_and_wait(chan, "vm-message");
08799 else
08800 res = ast_play_and_wait(chan, "vm-messages");
08801 }
08802
08803 }
08804 if (!res && vms->oldmessages) {
08805 res = say_and_wait(chan, vms->oldmessages, chan->language);
08806 if (!res) {
08807 if (vms->oldmessages == 1)
08808 res = ast_play_and_wait(chan, "vm-Olds");
08809 else
08810 res = ast_play_and_wait(chan, "vm-Old");
08811 }
08812 if (!res) {
08813 if (vms->oldmessages == 1)
08814 res = ast_play_and_wait(chan, "vm-message");
08815 else
08816 res = ast_play_and_wait(chan, "vm-messages");
08817 }
08818 }
08819 if (!res) {
08820 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08821 res = ast_play_and_wait(chan, "vm-no");
08822 if (!res)
08823 res = ast_play_and_wait(chan, "vm-messages");
08824 }
08825 }
08826 }
08827 return res;
08828 }
08829
08830
08831 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08832 {
08833
08834 int res;
08835 res = ast_play_and_wait(chan, "vm-youhave");
08836 if (!res) {
08837 if (vms->newmessages) {
08838 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08839 if (!res) {
08840 if ((vms->newmessages == 1)) {
08841 res = ast_play_and_wait(chan, "vm-message");
08842 if (!res)
08843 res = ast_play_and_wait(chan, "vm-INBOXs");
08844 } else {
08845 res = ast_play_and_wait(chan, "vm-messages");
08846 if (!res)
08847 res = ast_play_and_wait(chan, "vm-INBOX");
08848 }
08849 }
08850 if (vms->oldmessages && !res)
08851 res = ast_play_and_wait(chan, "vm-and");
08852 }
08853 if (!res && vms->oldmessages) {
08854 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08855 if (!res) {
08856 if (vms->oldmessages == 1) {
08857 res = ast_play_and_wait(chan, "vm-message");
08858 if (!res)
08859 res = ast_play_and_wait(chan, "vm-Olds");
08860 } else {
08861 res = ast_play_and_wait(chan, "vm-messages");
08862 if (!res)
08863 res = ast_play_and_wait(chan, "vm-Old");
08864 }
08865 }
08866 }
08867 if (!res) {
08868 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08869 res = ast_play_and_wait(chan, "vm-no");
08870 if (!res)
08871 res = ast_play_and_wait(chan, "vm-messages");
08872 }
08873 }
08874 }
08875 return res;
08876 }
08877
08878
08879
08880
08881
08882
08883
08884
08885
08886
08887
08888
08889
08890
08891
08892
08893
08894 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08895 {
08896 int res;
08897 res = ast_play_and_wait(chan, "vm-youhave");
08898 if (!res) {
08899 if (vms->newmessages) {
08900 if (vms->newmessages == 1) {
08901 res = ast_play_and_wait(chan, "digits/jednu");
08902 } else {
08903 res = say_and_wait(chan, vms->newmessages, chan->language);
08904 }
08905 if (!res) {
08906 if ((vms->newmessages == 1))
08907 res = ast_play_and_wait(chan, "vm-novou");
08908 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08909 res = ast_play_and_wait(chan, "vm-nove");
08910 if (vms->newmessages > 4)
08911 res = ast_play_and_wait(chan, "vm-novych");
08912 }
08913 if (vms->oldmessages && !res)
08914 res = ast_play_and_wait(chan, "vm-and");
08915 else if (!res) {
08916 if ((vms->newmessages == 1))
08917 res = ast_play_and_wait(chan, "vm-zpravu");
08918 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08919 res = ast_play_and_wait(chan, "vm-zpravy");
08920 if (vms->newmessages > 4)
08921 res = ast_play_and_wait(chan, "vm-zprav");
08922 }
08923 }
08924 if (!res && vms->oldmessages) {
08925 res = say_and_wait(chan, vms->oldmessages, chan->language);
08926 if (!res) {
08927 if ((vms->oldmessages == 1))
08928 res = ast_play_and_wait(chan, "vm-starou");
08929 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08930 res = ast_play_and_wait(chan, "vm-stare");
08931 if (vms->oldmessages > 4)
08932 res = ast_play_and_wait(chan, "vm-starych");
08933 }
08934 if (!res) {
08935 if ((vms->oldmessages == 1))
08936 res = ast_play_and_wait(chan, "vm-zpravu");
08937 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08938 res = ast_play_and_wait(chan, "vm-zpravy");
08939 if (vms->oldmessages > 4)
08940 res = ast_play_and_wait(chan, "vm-zprav");
08941 }
08942 }
08943 if (!res) {
08944 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08945 res = ast_play_and_wait(chan, "vm-no");
08946 if (!res)
08947 res = ast_play_and_wait(chan, "vm-zpravy");
08948 }
08949 }
08950 }
08951 return res;
08952 }
08953
08954
08955 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08956 {
08957 int res;
08958
08959 res = ast_play_and_wait(chan, "vm-you");
08960
08961 if (!res && vms->newmessages) {
08962 res = ast_play_and_wait(chan, "vm-have");
08963 if (!res)
08964 res = say_and_wait(chan, vms->newmessages, chan->language);
08965 if (!res)
08966 res = ast_play_and_wait(chan, "vm-tong");
08967 if (!res)
08968 res = ast_play_and_wait(chan, "vm-INBOX");
08969 if (vms->oldmessages && !res)
08970 res = ast_play_and_wait(chan, "vm-and");
08971 else if (!res)
08972 res = ast_play_and_wait(chan, "vm-messages");
08973 }
08974 if (!res && vms->oldmessages) {
08975 res = ast_play_and_wait(chan, "vm-have");
08976 if (!res)
08977 res = say_and_wait(chan, vms->oldmessages, chan->language);
08978 if (!res)
08979 res = ast_play_and_wait(chan, "vm-tong");
08980 if (!res)
08981 res = ast_play_and_wait(chan, "vm-Old");
08982 if (!res)
08983 res = ast_play_and_wait(chan, "vm-messages");
08984 }
08985 if (!res && !vms->oldmessages && !vms->newmessages) {
08986 res = ast_play_and_wait(chan, "vm-haveno");
08987 if (!res)
08988 res = ast_play_and_wait(chan, "vm-messages");
08989 }
08990 return res;
08991 }
08992
08993
08994 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
08995 {
08996 int res;
08997
08998
08999 res = ast_play_and_wait(chan, "vm-youhave");
09000 if (!res) {
09001 if (vms->newmessages) {
09002 res = say_and_wait(chan, vms->newmessages, chan->language);
09003 if (!res)
09004 res = ast_play_and_wait(chan, "vm-INBOX");
09005 if (vms->oldmessages && !res)
09006 res = ast_play_and_wait(chan, "vm-and");
09007 }
09008 if (!res && vms->oldmessages) {
09009 res = say_and_wait(chan, vms->oldmessages, chan->language);
09010 if (!res)
09011 res = ast_play_and_wait(chan, "vm-Old");
09012 }
09013 if (!res) {
09014 if (!vms->oldmessages && !vms->newmessages) {
09015 res = ast_play_and_wait(chan, "vm-no");
09016 if (!res)
09017 res = ast_play_and_wait(chan, "vm-message");
09018 }
09019 }
09020 }
09021 return res;
09022 }
09023
09024 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09025 {
09026 char prefile[256];
09027
09028
09029 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09030 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09031 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09032 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09033 ast_play_and_wait(chan, "vm-tempgreetactive");
09034 }
09035 DISPOSE(prefile, -1);
09036 }
09037
09038
09039 if (0) {
09040 return 0;
09041 } else if (!strncasecmp(chan->language, "cs", 2)) {
09042 return vm_intro_cs(chan, vms);
09043 } else if (!strncasecmp(chan->language, "cz", 2)) {
09044 static int deprecation_warning = 0;
09045 if (deprecation_warning++ % 10 == 0) {
09046 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09047 }
09048 return vm_intro_cs(chan, vms);
09049 } else if (!strncasecmp(chan->language, "de", 2)) {
09050 return vm_intro_de(chan, vms);
09051 } else if (!strncasecmp(chan->language, "es", 2)) {
09052 return vm_intro_es(chan, vms);
09053 } else if (!strncasecmp(chan->language, "fr", 2)) {
09054 return vm_intro_fr(chan, vms);
09055 } else if (!strncasecmp(chan->language, "gr", 2)) {
09056 return vm_intro_gr(chan, vms);
09057 } else if (!strncasecmp(chan->language, "he", 2)) {
09058 return vm_intro_he(chan, vms);
09059 } else if (!strncasecmp(chan->language, "it", 2)) {
09060 return vm_intro_it(chan, vms);
09061 } else if (!strncasecmp(chan->language, "nl", 2)) {
09062 return vm_intro_nl(chan, vms);
09063 } else if (!strncasecmp(chan->language, "no", 2)) {
09064 return vm_intro_no(chan, vms);
09065 } else if (!strncasecmp(chan->language, "pl", 2)) {
09066 return vm_intro_pl(chan, vms);
09067 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09068 return vm_intro_pt_BR(chan, vms);
09069 } else if (!strncasecmp(chan->language, "pt", 2)) {
09070 return vm_intro_pt(chan, vms);
09071 } else if (!strncasecmp(chan->language, "ru", 2)) {
09072 return vm_intro_multilang(chan, vms, "n");
09073 } else if (!strncasecmp(chan->language, "se", 2)) {
09074 return vm_intro_se(chan, vms);
09075 } else if (!strncasecmp(chan->language, "ua", 2)) {
09076 return vm_intro_multilang(chan, vms, "n");
09077 } else if (!strncasecmp(chan->language, "vi", 2)) {
09078 return vm_intro_vi(chan, vms);
09079 } else if (!strncasecmp(chan->language, "zh", 2)) {
09080 return vm_intro_zh(chan, vms);
09081 } else {
09082 return vm_intro_en(chan, vms);
09083 }
09084 }
09085
09086 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09087 {
09088 int res = 0;
09089
09090 while (!res) {
09091 if (vms->starting) {
09092 if (vms->lastmsg > -1) {
09093 if (skipadvanced)
09094 res = ast_play_and_wait(chan, "vm-onefor-full");
09095 else
09096 res = ast_play_and_wait(chan, "vm-onefor");
09097 if (!res)
09098 res = vm_play_folder_name(chan, vms->vmbox);
09099 }
09100 if (!res) {
09101 if (skipadvanced)
09102 res = ast_play_and_wait(chan, "vm-opts-full");
09103 else
09104 res = ast_play_and_wait(chan, "vm-opts");
09105 }
09106 } else {
09107
09108 if (skipadvanced) {
09109 res = ast_play_and_wait(chan, "vm-onefor-full");
09110 if (!res)
09111 res = vm_play_folder_name(chan, vms->vmbox);
09112 res = ast_play_and_wait(chan, "vm-opts-full");
09113 }
09114
09115
09116
09117
09118
09119
09120 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09121 res = ast_play_and_wait(chan, "vm-prev");
09122 }
09123 if (!res && !skipadvanced)
09124 res = ast_play_and_wait(chan, "vm-advopts");
09125 if (!res)
09126 res = ast_play_and_wait(chan, "vm-repeat");
09127
09128
09129
09130
09131
09132
09133 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09134 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09135 res = ast_play_and_wait(chan, "vm-next");
09136 }
09137 if (!res) {
09138 int curmsg_deleted;
09139 #ifdef IMAP_STORAGE
09140 ast_mutex_lock(&vms->lock);
09141 #endif
09142 curmsg_deleted = vms->deleted[vms->curmsg];
09143 #ifdef IMAP_STORAGE
09144 ast_mutex_unlock(&vms->lock);
09145 #endif
09146 if (!curmsg_deleted) {
09147 res = ast_play_and_wait(chan, "vm-delete");
09148 } else {
09149 res = ast_play_and_wait(chan, "vm-undelete");
09150 }
09151 if (!res) {
09152 res = ast_play_and_wait(chan, "vm-toforward");
09153 }
09154 if (!res) {
09155 res = ast_play_and_wait(chan, "vm-savemessage");
09156 }
09157 }
09158 }
09159 if (!res) {
09160 res = ast_play_and_wait(chan, "vm-helpexit");
09161 }
09162 if (!res)
09163 res = ast_waitfordigit(chan, 6000);
09164 if (!res) {
09165 vms->repeats++;
09166 if (vms->repeats > 2) {
09167 res = 't';
09168 }
09169 }
09170 }
09171 return res;
09172 }
09173
09174 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09175 {
09176 int res = 0;
09177
09178 while (!res) {
09179 if (vms->lastmsg > -1) {
09180 res = ast_play_and_wait(chan, "vm-listen");
09181 if (!res)
09182 res = vm_play_folder_name(chan, vms->vmbox);
09183 if (!res)
09184 res = ast_play_and_wait(chan, "press");
09185 if (!res)
09186 res = ast_play_and_wait(chan, "digits/1");
09187 }
09188 if (!res)
09189 res = ast_play_and_wait(chan, "vm-opts");
09190 if (!res) {
09191 vms->starting = 0;
09192 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09193 }
09194 }
09195 return res;
09196 }
09197
09198 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09199 {
09200 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09201 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09202 } else {
09203 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09204 }
09205 }
09206
09207
09208 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09209 {
09210 int cmd = 0;
09211 int duration = 0;
09212 int tries = 0;
09213 char newpassword[80] = "";
09214 char newpassword2[80] = "";
09215 char prefile[PATH_MAX] = "";
09216 unsigned char buf[256];
09217 int bytes = 0;
09218
09219 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09220 if (ast_adsi_available(chan)) {
09221 bytes += adsi_logo(buf + bytes);
09222 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09223 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09224 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09225 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09226 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09227 }
09228
09229
09230 if (ast_test_flag(vmu, VM_FORCENAME)) {
09231 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09232 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09233 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09234 if (cmd < 0 || cmd == 't' || cmd == '#')
09235 return cmd;
09236 }
09237 }
09238
09239
09240 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09241 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09242 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09243 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09244 if (cmd < 0 || cmd == 't' || cmd == '#')
09245 return cmd;
09246 }
09247
09248 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09249 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09250 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09251 if (cmd < 0 || cmd == 't' || cmd == '#')
09252 return cmd;
09253 }
09254 }
09255
09256
09257
09258
09259
09260 for (;;) {
09261 newpassword[1] = '\0';
09262 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09263 if (cmd == '#')
09264 newpassword[0] = '\0';
09265 if (cmd < 0 || cmd == 't' || cmd == '#')
09266 return cmd;
09267 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09268 if (cmd < 0 || cmd == 't' || cmd == '#')
09269 return cmd;
09270 cmd = check_password(vmu, newpassword);
09271 if (cmd != 0) {
09272 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09273 cmd = ast_play_and_wait(chan, vm_invalid_password);
09274 } else {
09275 newpassword2[1] = '\0';
09276 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09277 if (cmd == '#')
09278 newpassword2[0] = '\0';
09279 if (cmd < 0 || cmd == 't' || cmd == '#')
09280 return cmd;
09281 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09282 if (cmd < 0 || cmd == 't' || cmd == '#')
09283 return cmd;
09284 if (!strcmp(newpassword, newpassword2))
09285 break;
09286 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09287 cmd = ast_play_and_wait(chan, vm_mismatch);
09288 }
09289 if (++tries == 3)
09290 return -1;
09291 if (cmd != 0) {
09292 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09293 }
09294 }
09295 if (pwdchange & PWDCHANGE_INTERNAL)
09296 vm_change_password(vmu, newpassword);
09297 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09298 vm_change_password_shell(vmu, newpassword);
09299
09300 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09301 cmd = ast_play_and_wait(chan, vm_passchanged);
09302
09303 return cmd;
09304 }
09305
09306 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09307 {
09308 int cmd = 0;
09309 int retries = 0;
09310 int duration = 0;
09311 char newpassword[80] = "";
09312 char newpassword2[80] = "";
09313 char prefile[PATH_MAX] = "";
09314 unsigned char buf[256];
09315 int bytes = 0;
09316
09317 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09318 if (ast_adsi_available(chan)) {
09319 bytes += adsi_logo(buf + bytes);
09320 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09321 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09322 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09323 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09324 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09325 }
09326 while ((cmd >= 0) && (cmd != 't')) {
09327 if (cmd)
09328 retries = 0;
09329 switch (cmd) {
09330 case '1':
09331 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09332 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09333 break;
09334 case '2':
09335 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09336 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09337 break;
09338 case '3':
09339 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09340 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09341 break;
09342 case '4':
09343 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09344 break;
09345 case '5':
09346 if (vmu->password[0] == '-') {
09347 cmd = ast_play_and_wait(chan, "vm-no");
09348 break;
09349 }
09350 newpassword[1] = '\0';
09351 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09352 if (cmd == '#')
09353 newpassword[0] = '\0';
09354 else {
09355 if (cmd < 0)
09356 break;
09357 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09358 break;
09359 }
09360 }
09361 cmd = check_password(vmu, newpassword);
09362 if (cmd != 0) {
09363 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09364 cmd = ast_play_and_wait(chan, vm_invalid_password);
09365 if (!cmd) {
09366 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09367 }
09368 break;
09369 }
09370 newpassword2[1] = '\0';
09371 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09372 if (cmd == '#')
09373 newpassword2[0] = '\0';
09374 else {
09375 if (cmd < 0)
09376 break;
09377
09378 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09379 break;
09380 }
09381 }
09382 if (strcmp(newpassword, newpassword2)) {
09383 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09384 cmd = ast_play_and_wait(chan, vm_mismatch);
09385 if (!cmd) {
09386 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09387 }
09388 break;
09389 }
09390
09391 if (pwdchange & PWDCHANGE_INTERNAL) {
09392 vm_change_password(vmu, newpassword);
09393 }
09394 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09395 vm_change_password_shell(vmu, newpassword);
09396 }
09397
09398 ast_debug(1, "User %s set password to %s of length %d\n",
09399 vms->username, newpassword, (int) strlen(newpassword));
09400 cmd = ast_play_and_wait(chan, vm_passchanged);
09401 break;
09402 case '*':
09403 cmd = 't';
09404 break;
09405 default:
09406 cmd = 0;
09407 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09408 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09409 if (ast_fileexists(prefile, NULL, NULL)) {
09410 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09411 }
09412 DISPOSE(prefile, -1);
09413 if (!cmd) {
09414 cmd = ast_play_and_wait(chan, "vm-options");
09415 }
09416 if (!cmd) {
09417 cmd = ast_waitfordigit(chan, 6000);
09418 }
09419 if (!cmd) {
09420 retries++;
09421 }
09422 if (retries > 3) {
09423 cmd = 't';
09424 }
09425 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09426 }
09427 }
09428 if (cmd == 't')
09429 cmd = 0;
09430 return cmd;
09431 }
09432
09433
09434
09435
09436
09437
09438
09439
09440
09441
09442
09443
09444
09445
09446
09447
09448
09449 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09450 {
09451 int cmd = 0;
09452 int retries = 0;
09453 int duration = 0;
09454 char prefile[PATH_MAX] = "";
09455 unsigned char buf[256];
09456 int bytes = 0;
09457
09458 if (ast_adsi_available(chan)) {
09459 bytes += adsi_logo(buf + bytes);
09460 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09461 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09462 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09463 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09464 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09465 }
09466
09467 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09468 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09469 while ((cmd >= 0) && (cmd != 't')) {
09470 if (cmd)
09471 retries = 0;
09472 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09473 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09474 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09475 if (cmd == -1) {
09476 break;
09477 }
09478 cmd = 't';
09479 } else {
09480 switch (cmd) {
09481 case '1':
09482 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09483 break;
09484 case '2':
09485 DELETE(prefile, -1, prefile, vmu);
09486 ast_play_and_wait(chan, "vm-tempremoved");
09487 cmd = 't';
09488 break;
09489 case '*':
09490 cmd = 't';
09491 break;
09492 default:
09493 cmd = ast_play_and_wait(chan,
09494 ast_fileexists(prefile, NULL, NULL) > 0 ?
09495 "vm-tempgreeting2" : "vm-tempgreeting");
09496 if (!cmd) {
09497 cmd = ast_waitfordigit(chan, 6000);
09498 }
09499 if (!cmd) {
09500 retries++;
09501 }
09502 if (retries > 3) {
09503 cmd = 't';
09504 }
09505 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09506 }
09507 }
09508 DISPOSE(prefile, -1);
09509 }
09510 if (cmd == 't')
09511 cmd = 0;
09512 return cmd;
09513 }
09514
09515
09516
09517
09518
09519
09520
09521
09522
09523 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09524 {
09525 int cmd = 0;
09526
09527 if (vms->lastmsg > -1) {
09528 cmd = play_message(chan, vmu, vms);
09529 } else {
09530 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09531 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09532 if (!cmd) {
09533 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09534 cmd = ast_play_and_wait(chan, vms->fn);
09535 }
09536 if (!cmd)
09537 cmd = ast_play_and_wait(chan, "vm-messages");
09538 } else {
09539 if (!cmd)
09540 cmd = ast_play_and_wait(chan, "vm-messages");
09541 if (!cmd) {
09542 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09543 cmd = ast_play_and_wait(chan, vms->fn);
09544 }
09545 }
09546 }
09547 return cmd;
09548 }
09549
09550
09551 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09552 {
09553 int cmd = 0;
09554
09555 if (vms->lastmsg > -1) {
09556 cmd = play_message(chan, vmu, vms);
09557 } else {
09558 if (!strcasecmp(vms->fn, "INBOX")) {
09559 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09560 } else {
09561 cmd = ast_play_and_wait(chan, "vm-nomessages");
09562 }
09563 }
09564 return cmd;
09565 }
09566
09567
09568
09569
09570
09571
09572
09573
09574
09575 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09576 {
09577 int cmd = 0;
09578
09579 if (vms->lastmsg > -1) {
09580 cmd = play_message(chan, vmu, vms);
09581 } else {
09582 cmd = ast_play_and_wait(chan, "vm-youhave");
09583 if (!cmd)
09584 cmd = ast_play_and_wait(chan, "vm-no");
09585 if (!cmd) {
09586 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09587 cmd = ast_play_and_wait(chan, vms->fn);
09588 }
09589 if (!cmd)
09590 cmd = ast_play_and_wait(chan, "vm-messages");
09591 }
09592 return cmd;
09593 }
09594
09595
09596
09597
09598
09599
09600
09601
09602
09603 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09604 {
09605 int cmd;
09606
09607 if (vms->lastmsg > -1) {
09608 cmd = play_message(chan, vmu, vms);
09609 } else {
09610 cmd = ast_play_and_wait(chan, "vm-no");
09611 if (!cmd)
09612 cmd = ast_play_and_wait(chan, "vm-message");
09613 if (!cmd) {
09614 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09615 cmd = ast_play_and_wait(chan, vms->fn);
09616 }
09617 }
09618 return cmd;
09619 }
09620
09621
09622
09623
09624
09625
09626
09627
09628
09629 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09630 {
09631 int cmd;
09632
09633 if (vms->lastmsg > -1) {
09634 cmd = play_message(chan, vmu, vms);
09635 } else {
09636 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09637 if (!cmd)
09638 cmd = ast_play_and_wait(chan, "vm-messages");
09639 if (!cmd) {
09640 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09641 cmd = ast_play_and_wait(chan, vms->fn);
09642 }
09643 }
09644 return cmd;
09645 }
09646
09647
09648
09649
09650
09651
09652
09653
09654
09655 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09656 {
09657 int cmd;
09658
09659 if (vms->lastmsg > -1) {
09660 cmd = play_message(chan, vmu, vms);
09661 } else {
09662 cmd = ast_play_and_wait(chan, "vm-no");
09663 if (!cmd) {
09664 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09665 cmd = ast_play_and_wait(chan, vms->fn);
09666 }
09667 if (!cmd)
09668 cmd = ast_play_and_wait(chan, "vm-messages");
09669 }
09670 return cmd;
09671 }
09672
09673
09674
09675
09676
09677
09678
09679
09680
09681 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09682 {
09683 int cmd;
09684
09685 if (vms->lastmsg > -1) {
09686 cmd = play_message(chan, vmu, vms);
09687 } else {
09688 cmd = ast_play_and_wait(chan, "vm-you");
09689 if (!cmd)
09690 cmd = ast_play_and_wait(chan, "vm-haveno");
09691 if (!cmd)
09692 cmd = ast_play_and_wait(chan, "vm-messages");
09693 if (!cmd) {
09694 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09695 cmd = ast_play_and_wait(chan, vms->fn);
09696 }
09697 }
09698 return cmd;
09699 }
09700
09701
09702
09703
09704
09705
09706
09707
09708
09709 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09710 {
09711 int cmd = 0;
09712
09713 if (vms->lastmsg > -1) {
09714 cmd = play_message(chan, vmu, vms);
09715 } else {
09716 cmd = ast_play_and_wait(chan, "vm-no");
09717 if (!cmd) {
09718 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09719 cmd = ast_play_and_wait(chan, vms->fn);
09720 }
09721 }
09722 return cmd;
09723 }
09724
09725
09726
09727
09728
09729
09730
09731
09732
09733
09734
09735
09736 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09737 {
09738 if (!strncasecmp(chan->language, "es", 2)) {
09739 return vm_browse_messages_es(chan, vms, vmu);
09740 } else if (!strncasecmp(chan->language, "gr", 2)) {
09741 return vm_browse_messages_gr(chan, vms, vmu);
09742 } else if (!strncasecmp(chan->language, "he", 2)) {
09743 return vm_browse_messages_he(chan, vms, vmu);
09744 } else if (!strncasecmp(chan->language, "it", 2)) {
09745 return vm_browse_messages_it(chan, vms, vmu);
09746 } else if (!strncasecmp(chan->language, "pt", 2)) {
09747 return vm_browse_messages_pt(chan, vms, vmu);
09748 } else if (!strncasecmp(chan->language, "vi", 2)) {
09749 return vm_browse_messages_vi(chan, vms, vmu);
09750 } else if (!strncasecmp(chan->language, "zh", 2)) {
09751 return vm_browse_messages_zh(chan, vms, vmu);
09752 } else {
09753 return vm_browse_messages_en(chan, vms, vmu);
09754 }
09755 }
09756
09757 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09758 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09759 int skipuser, int max_logins, int silent)
09760 {
09761 int useadsi = 0, valid = 0, logretries = 0;
09762 char password[AST_MAX_EXTENSION]="", *passptr;
09763 struct ast_vm_user vmus, *vmu = NULL;
09764
09765
09766 adsi_begin(chan, &useadsi);
09767 if (!skipuser && useadsi)
09768 adsi_login(chan);
09769 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09770 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09771 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09772 return -1;
09773 }
09774
09775
09776
09777 while (!valid && (logretries < max_logins)) {
09778
09779 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09780 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09781 return -1;
09782 }
09783 if (ast_strlen_zero(mailbox)) {
09784 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09785 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09786 } else {
09787 ast_verb(3, "Username not entered\n");
09788 return -1;
09789 }
09790 } else if (mailbox[0] == '*') {
09791
09792 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09793 if (ast_exists_extension(chan, chan->context, "a", 1,
09794 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09795 return -1;
09796 }
09797 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09798 mailbox[0] = '\0';
09799 }
09800
09801 if (useadsi)
09802 adsi_password(chan);
09803
09804 if (!ast_strlen_zero(prefix)) {
09805 char fullusername[80] = "";
09806 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09807 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09808 ast_copy_string(mailbox, fullusername, mailbox_size);
09809 }
09810
09811 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09812 vmu = find_user(&vmus, context, mailbox);
09813 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09814
09815 password[0] = '\0';
09816 } else {
09817 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09818 if (ast_streamfile(chan, vm_password, chan->language)) {
09819 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09820 return -1;
09821 }
09822 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09823 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09824 return -1;
09825 } else if (password[0] == '*') {
09826
09827 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09828 if (ast_exists_extension(chan, chan->context, "a", 1,
09829 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09830 mailbox[0] = '*';
09831 return -1;
09832 }
09833 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09834 mailbox[0] = '\0';
09835
09836 vmu = NULL;
09837 }
09838 }
09839
09840 if (vmu) {
09841 passptr = vmu->password;
09842 if (passptr[0] == '-') passptr++;
09843 }
09844 if (vmu && !strcmp(passptr, password))
09845 valid++;
09846 else {
09847 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09848 if (!ast_strlen_zero(prefix))
09849 mailbox[0] = '\0';
09850 }
09851 logretries++;
09852 if (!valid) {
09853 if (skipuser || logretries >= max_logins) {
09854 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09855 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09856 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09857 return -1;
09858 }
09859 } else {
09860 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09861 if (useadsi)
09862 adsi_login(chan);
09863 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09864 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09865 return -1;
09866 }
09867 }
09868 if (ast_waitstream(chan, ""))
09869 return -1;
09870 }
09871 }
09872 if (!valid && (logretries >= max_logins)) {
09873 ast_stopstream(chan);
09874 ast_play_and_wait(chan, "vm-goodbye");
09875 return -1;
09876 }
09877 if (vmu && !skipuser) {
09878 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09879 }
09880 return 0;
09881 }
09882
09883 static int vm_execmain(struct ast_channel *chan, const char *data)
09884 {
09885
09886
09887
09888 int res = -1;
09889 int cmd = 0;
09890 int valid = 0;
09891 char prefixstr[80] ="";
09892 char ext_context[256]="";
09893 int box;
09894 int useadsi = 0;
09895 int skipuser = 0;
09896 struct vm_state vms;
09897 struct ast_vm_user *vmu = NULL, vmus;
09898 char *context = NULL;
09899 int silentexit = 0;
09900 struct ast_flags flags = { 0 };
09901 signed char record_gain = 0;
09902 int play_auto = 0;
09903 int play_folder = 0;
09904 int in_urgent = 0;
09905 #ifdef IMAP_STORAGE
09906 int deleted = 0;
09907 #endif
09908
09909
09910 memset(&vms, 0, sizeof(vms));
09911
09912 vms.lastmsg = -1;
09913
09914 memset(&vmus, 0, sizeof(vmus));
09915
09916 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09917 if (chan->_state != AST_STATE_UP) {
09918 ast_debug(1, "Before ast_answer\n");
09919 ast_answer(chan);
09920 }
09921
09922 if (!ast_strlen_zero(data)) {
09923 char *opts[OPT_ARG_ARRAY_SIZE];
09924 char *parse;
09925 AST_DECLARE_APP_ARGS(args,
09926 AST_APP_ARG(argv0);
09927 AST_APP_ARG(argv1);
09928 );
09929
09930 parse = ast_strdupa(data);
09931
09932 AST_STANDARD_APP_ARGS(args, parse);
09933
09934 if (args.argc == 2) {
09935 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09936 return -1;
09937 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09938 int gain;
09939 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09940 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09941 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09942 return -1;
09943 } else {
09944 record_gain = (signed char) gain;
09945 }
09946 } else {
09947 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09948 }
09949 }
09950 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09951 play_auto = 1;
09952 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09953
09954 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09955 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09956 play_folder = -1;
09957 }
09958 } else {
09959 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09960 }
09961 } else {
09962 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09963 }
09964 if (play_folder > 9 || play_folder < 0) {
09965 ast_log(AST_LOG_WARNING,
09966 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09967 opts[OPT_ARG_PLAYFOLDER]);
09968 play_folder = 0;
09969 }
09970 }
09971 } else {
09972
09973 while (*(args.argv0)) {
09974 if (*(args.argv0) == 's')
09975 ast_set_flag(&flags, OPT_SILENT);
09976 else if (*(args.argv0) == 'p')
09977 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09978 else
09979 break;
09980 (args.argv0)++;
09981 }
09982
09983 }
09984
09985 valid = ast_test_flag(&flags, OPT_SILENT);
09986
09987 if ((context = strchr(args.argv0, '@')))
09988 *context++ = '\0';
09989
09990 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09991 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09992 else
09993 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09994
09995 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09996 skipuser++;
09997 else
09998 valid = 0;
09999 }
10000
10001 if (!valid)
10002 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10003
10004 ast_debug(1, "After vm_authenticate\n");
10005
10006 if (vms.username[0] == '*') {
10007 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10008
10009
10010 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10011 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10012 res = 0;
10013 goto out;
10014 }
10015 }
10016
10017 if (!res) {
10018 valid = 1;
10019 if (!skipuser)
10020 vmu = &vmus;
10021 } else {
10022 res = 0;
10023 }
10024
10025
10026 adsi_begin(chan, &useadsi);
10027
10028 ast_test_suite_assert(valid);
10029 if (!valid) {
10030 goto out;
10031 }
10032 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10033
10034 #ifdef IMAP_STORAGE
10035 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10036 pthread_setspecific(ts_vmstate.key, &vms);
10037
10038 vms.interactive = 1;
10039 vms.updated = 1;
10040 if (vmu)
10041 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10042 vmstate_insert(&vms);
10043 init_vm_state(&vms);
10044 #endif
10045
10046
10047 if (!ast_strlen_zero(vmu->language))
10048 ast_string_field_set(chan, language, vmu->language);
10049
10050
10051 ast_debug(1, "Before open_mailbox\n");
10052 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10053 if (res < 0)
10054 goto out;
10055 vms.oldmessages = vms.lastmsg + 1;
10056 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10057
10058 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10059 if (res < 0)
10060 goto out;
10061 vms.newmessages = vms.lastmsg + 1;
10062 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10063
10064 in_urgent = 1;
10065 res = open_mailbox(&vms, vmu, 11);
10066 if (res < 0)
10067 goto out;
10068 vms.urgentmessages = vms.lastmsg + 1;
10069 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10070
10071
10072 if (play_auto) {
10073 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10074 if (vms.urgentmessages) {
10075 in_urgent = 1;
10076 res = open_mailbox(&vms, vmu, 11);
10077 } else {
10078 in_urgent = 0;
10079 res = open_mailbox(&vms, vmu, play_folder);
10080 }
10081 if (res < 0)
10082 goto out;
10083
10084
10085 if (vms.lastmsg == -1) {
10086 in_urgent = 0;
10087 cmd = vm_browse_messages(chan, &vms, vmu);
10088 res = 0;
10089 goto out;
10090 }
10091 } else {
10092 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10093
10094 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10095 in_urgent = 0;
10096 play_folder = 1;
10097 if (res < 0)
10098 goto out;
10099 } else if (!vms.urgentmessages && vms.newmessages) {
10100
10101 in_urgent = 0;
10102 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10103 if (res < 0)
10104 goto out;
10105 }
10106 }
10107
10108 if (useadsi)
10109 adsi_status(chan, &vms);
10110 res = 0;
10111
10112
10113 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10114 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10115 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10116 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10117 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10118 if ((cmd == 't') || (cmd == '#')) {
10119
10120 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10121 res = 0;
10122 goto out;
10123 } else if (cmd < 0) {
10124
10125 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10126 res = -1;
10127 goto out;
10128 }
10129 }
10130 #ifdef IMAP_STORAGE
10131 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10132 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10133 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10134 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10135 }
10136 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10137 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10138 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10139 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10140 }
10141 #endif
10142
10143 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10144 if (play_auto) {
10145 cmd = '1';
10146 } else {
10147 cmd = vm_intro(chan, vmu, &vms);
10148 }
10149 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10150
10151 vms.repeats = 0;
10152 vms.starting = 1;
10153 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10154
10155 switch (cmd) {
10156 case '1':
10157 vms.curmsg = 0;
10158
10159 case '5':
10160 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10161 cmd = vm_browse_messages(chan, &vms, vmu);
10162 break;
10163 case '2':
10164 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10165 if (useadsi)
10166 adsi_folders(chan, 0, "Change to folder...");
10167
10168 cmd = get_folder2(chan, "vm-changeto", 0);
10169 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10170 if (cmd == '#') {
10171 cmd = 0;
10172 } else if (cmd > 0) {
10173 cmd = cmd - '0';
10174 res = close_mailbox(&vms, vmu);
10175 if (res == ERROR_LOCK_PATH)
10176 goto out;
10177
10178 if (cmd != 11) in_urgent = 0;
10179 res = open_mailbox(&vms, vmu, cmd);
10180 if (res < 0)
10181 goto out;
10182 play_folder = cmd;
10183 cmd = 0;
10184 }
10185 if (useadsi)
10186 adsi_status2(chan, &vms);
10187
10188 if (!cmd) {
10189 cmd = vm_play_folder_name(chan, vms.vmbox);
10190 }
10191
10192 vms.starting = 1;
10193 vms.curmsg = 0;
10194 break;
10195 case '3':
10196 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10197 cmd = 0;
10198 vms.repeats = 0;
10199 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10200 switch (cmd) {
10201 case '1':
10202 if (vms.lastmsg > -1 && !vms.starting) {
10203 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10204 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10205 res = cmd;
10206 goto out;
10207 }
10208 } else {
10209 cmd = ast_play_and_wait(chan, "vm-sorry");
10210 }
10211 cmd = 't';
10212 break;
10213 case '2':
10214 if (!vms.starting)
10215 ast_verb(3, "Callback Requested\n");
10216 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10217 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10218 if (cmd == 9) {
10219 silentexit = 1;
10220 goto out;
10221 } else if (cmd == ERROR_LOCK_PATH) {
10222 res = cmd;
10223 goto out;
10224 }
10225 } else {
10226 cmd = ast_play_and_wait(chan, "vm-sorry");
10227 }
10228 cmd = 't';
10229 break;
10230 case '3':
10231 if (vms.lastmsg > -1 && !vms.starting) {
10232 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10233 if (cmd == ERROR_LOCK_PATH) {
10234 res = cmd;
10235 goto out;
10236 }
10237 } else {
10238 cmd = ast_play_and_wait(chan, "vm-sorry");
10239 }
10240 cmd = 't';
10241 break;
10242 case '4':
10243 if (!ast_strlen_zero(vmu->dialout)) {
10244 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10245 if (cmd == 9) {
10246 silentexit = 1;
10247 goto out;
10248 }
10249 } else {
10250 cmd = ast_play_and_wait(chan, "vm-sorry");
10251 }
10252 cmd = 't';
10253 break;
10254
10255 case '5':
10256 if (ast_test_flag(vmu, VM_SVMAIL)) {
10257 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10258 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10259 res = cmd;
10260 goto out;
10261 }
10262 } else {
10263 cmd = ast_play_and_wait(chan, "vm-sorry");
10264 }
10265 cmd = 't';
10266 break;
10267
10268 case '*':
10269 cmd = 't';
10270 break;
10271
10272 default:
10273 cmd = 0;
10274 if (!vms.starting) {
10275 cmd = ast_play_and_wait(chan, "vm-toreply");
10276 }
10277 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10278 cmd = ast_play_and_wait(chan, "vm-tocallback");
10279 }
10280 if (!cmd && !vms.starting) {
10281 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10282 }
10283 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10284 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10285 }
10286 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10287 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10288 }
10289 if (!cmd) {
10290 cmd = ast_play_and_wait(chan, "vm-starmain");
10291 }
10292 if (!cmd) {
10293 cmd = ast_waitfordigit(chan, 6000);
10294 }
10295 if (!cmd) {
10296 vms.repeats++;
10297 }
10298 if (vms.repeats > 3) {
10299 cmd = 't';
10300 }
10301 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10302 }
10303 }
10304 if (cmd == 't') {
10305 cmd = 0;
10306 vms.repeats = 0;
10307 }
10308 break;
10309 case '4':
10310 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10311 if (vms.curmsg > 0) {
10312 vms.curmsg--;
10313 cmd = play_message(chan, vmu, &vms);
10314 } else {
10315
10316
10317
10318
10319 if (in_urgent == 0 && vms.urgentmessages > 0) {
10320
10321 in_urgent = 1;
10322 res = close_mailbox(&vms, vmu);
10323 if (res == ERROR_LOCK_PATH)
10324 goto out;
10325 res = open_mailbox(&vms, vmu, 11);
10326 if (res < 0)
10327 goto out;
10328 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10329 vms.curmsg = vms.lastmsg;
10330 if (vms.lastmsg < 0) {
10331 cmd = ast_play_and_wait(chan, "vm-nomore");
10332 }
10333 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10334 vms.curmsg = vms.lastmsg;
10335 cmd = play_message(chan, vmu, &vms);
10336 } else {
10337 cmd = ast_play_and_wait(chan, "vm-nomore");
10338 }
10339 }
10340 break;
10341 case '6':
10342 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10343 if (vms.curmsg < vms.lastmsg) {
10344 vms.curmsg++;
10345 cmd = play_message(chan, vmu, &vms);
10346 } else {
10347 if (in_urgent && vms.newmessages > 0) {
10348
10349
10350
10351
10352 in_urgent = 0;
10353 res = close_mailbox(&vms, vmu);
10354 if (res == ERROR_LOCK_PATH)
10355 goto out;
10356 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10357 if (res < 0)
10358 goto out;
10359 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10360 vms.curmsg = -1;
10361 if (vms.lastmsg < 0) {
10362 cmd = ast_play_and_wait(chan, "vm-nomore");
10363 }
10364 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10365 vms.curmsg = 0;
10366 cmd = play_message(chan, vmu, &vms);
10367 } else {
10368 cmd = ast_play_and_wait(chan, "vm-nomore");
10369 }
10370 }
10371 break;
10372 case '7':
10373 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10374 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10375 if (useadsi)
10376 adsi_delete(chan, &vms);
10377 if (vms.deleted[vms.curmsg]) {
10378 if (play_folder == 0) {
10379 if (in_urgent) {
10380 vms.urgentmessages--;
10381 } else {
10382 vms.newmessages--;
10383 }
10384 }
10385 else if (play_folder == 1)
10386 vms.oldmessages--;
10387 cmd = ast_play_and_wait(chan, "vm-deleted");
10388 } else {
10389 if (play_folder == 0) {
10390 if (in_urgent) {
10391 vms.urgentmessages++;
10392 } else {
10393 vms.newmessages++;
10394 }
10395 }
10396 else if (play_folder == 1)
10397 vms.oldmessages++;
10398 cmd = ast_play_and_wait(chan, "vm-undeleted");
10399 }
10400 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10401 if (vms.curmsg < vms.lastmsg) {
10402 vms.curmsg++;
10403 cmd = play_message(chan, vmu, &vms);
10404 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10405 vms.curmsg = 0;
10406 cmd = play_message(chan, vmu, &vms);
10407 } else {
10408
10409
10410
10411
10412 if (in_urgent == 1) {
10413
10414 in_urgent = 0;
10415 res = close_mailbox(&vms, vmu);
10416 if (res == ERROR_LOCK_PATH)
10417 goto out;
10418 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10419 if (res < 0)
10420 goto out;
10421 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10422 vms.curmsg = -1;
10423 if (vms.lastmsg < 0) {
10424 cmd = ast_play_and_wait(chan, "vm-nomore");
10425 }
10426 } else {
10427 cmd = ast_play_and_wait(chan, "vm-nomore");
10428 }
10429 }
10430 }
10431 } else
10432 cmd = 0;
10433 #ifdef IMAP_STORAGE
10434 deleted = 1;
10435 #endif
10436 break;
10437
10438 case '8':
10439 if (vms.lastmsg > -1) {
10440 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10441 if (cmd == ERROR_LOCK_PATH) {
10442 res = cmd;
10443 goto out;
10444 }
10445 } else {
10446
10447
10448
10449
10450 if (in_urgent == 1 && vms.newmessages > 0) {
10451
10452 in_urgent = 0;
10453 res = close_mailbox(&vms, vmu);
10454 if (res == ERROR_LOCK_PATH)
10455 goto out;
10456 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10457 if (res < 0)
10458 goto out;
10459 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10460 vms.curmsg = -1;
10461 if (vms.lastmsg < 0) {
10462 cmd = ast_play_and_wait(chan, "vm-nomore");
10463 }
10464 } else {
10465 cmd = ast_play_and_wait(chan, "vm-nomore");
10466 }
10467 }
10468 break;
10469 case '9':
10470 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10471 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10472
10473 cmd = 0;
10474 break;
10475 }
10476 if (useadsi)
10477 adsi_folders(chan, 1, "Save to folder...");
10478 cmd = get_folder2(chan, "vm-savefolder", 1);
10479 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10480 box = 0;
10481 if (cmd == '#') {
10482 cmd = 0;
10483 break;
10484 } else if (cmd > 0) {
10485 box = cmd = cmd - '0';
10486 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10487 if (cmd == ERROR_LOCK_PATH) {
10488 res = cmd;
10489 goto out;
10490 #ifndef IMAP_STORAGE
10491 } else if (!cmd) {
10492 vms.deleted[vms.curmsg] = 1;
10493 #endif
10494 } else {
10495 vms.deleted[vms.curmsg] = 0;
10496 vms.heard[vms.curmsg] = 0;
10497 }
10498 }
10499 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10500 if (useadsi)
10501 adsi_message(chan, &vms);
10502 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10503 if (!cmd) {
10504 cmd = ast_play_and_wait(chan, "vm-message");
10505 if (!cmd)
10506 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10507 if (!cmd)
10508 cmd = ast_play_and_wait(chan, "vm-savedto");
10509 if (!cmd)
10510 cmd = vm_play_folder_name(chan, vms.fn);
10511 } else {
10512 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10513 }
10514 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10515 if (vms.curmsg < vms.lastmsg) {
10516 vms.curmsg++;
10517 cmd = play_message(chan, vmu, &vms);
10518 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10519 vms.curmsg = 0;
10520 cmd = play_message(chan, vmu, &vms);
10521 } else {
10522
10523
10524
10525
10526 if (in_urgent == 1 && vms.newmessages > 0) {
10527
10528 in_urgent = 0;
10529 res = close_mailbox(&vms, vmu);
10530 if (res == ERROR_LOCK_PATH)
10531 goto out;
10532 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10533 if (res < 0)
10534 goto out;
10535 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10536 vms.curmsg = -1;
10537 if (vms.lastmsg < 0) {
10538 cmd = ast_play_and_wait(chan, "vm-nomore");
10539 }
10540 } else {
10541 cmd = ast_play_and_wait(chan, "vm-nomore");
10542 }
10543 }
10544 }
10545 break;
10546 case '*':
10547 if (!vms.starting) {
10548 cmd = ast_play_and_wait(chan, "vm-onefor");
10549 if (!strncasecmp(chan->language, "he", 2)) {
10550 cmd = ast_play_and_wait(chan, "vm-for");
10551 }
10552 if (!cmd)
10553 cmd = vm_play_folder_name(chan, vms.vmbox);
10554 if (!cmd)
10555 cmd = ast_play_and_wait(chan, "vm-opts");
10556 if (!cmd)
10557 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10558 } else
10559 cmd = 0;
10560 break;
10561 case '0':
10562 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10563 if (useadsi)
10564 adsi_status(chan, &vms);
10565 break;
10566 default:
10567 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10568 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10569 break;
10570 }
10571 }
10572 if ((cmd == 't') || (cmd == '#')) {
10573
10574 res = 0;
10575 } else {
10576
10577 res = -1;
10578 }
10579
10580 out:
10581 if (res > -1) {
10582 ast_stopstream(chan);
10583 adsi_goodbye(chan);
10584 if (valid && res != OPERATOR_EXIT) {
10585 if (silentexit)
10586 res = ast_play_and_wait(chan, "vm-dialout");
10587 else
10588 res = ast_play_and_wait(chan, "vm-goodbye");
10589 }
10590 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10591 res = 0;
10592 }
10593 if (useadsi)
10594 ast_adsi_unload_session(chan);
10595 }
10596 if (vmu)
10597 close_mailbox(&vms, vmu);
10598 if (valid) {
10599 int new = 0, old = 0, urgent = 0;
10600 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10601 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10602
10603 run_externnotify(vmu->context, vmu->mailbox, NULL);
10604 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10605 queue_mwi_event(ext_context, urgent, new, old);
10606 }
10607 #ifdef IMAP_STORAGE
10608
10609 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10610 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10611 ast_mutex_lock(&vms.lock);
10612 #ifdef HAVE_IMAP_TK2006
10613 if (LEVELUIDPLUS (vms.mailstream)) {
10614 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10615 } else
10616 #endif
10617 mail_expunge(vms.mailstream);
10618 ast_mutex_unlock(&vms.lock);
10619 }
10620
10621
10622 if (vmu) {
10623 vmstate_delete(&vms);
10624 }
10625 #endif
10626 if (vmu)
10627 free_user(vmu);
10628
10629 #ifdef IMAP_STORAGE
10630 pthread_setspecific(ts_vmstate.key, NULL);
10631 #endif
10632 return res;
10633 }
10634
10635 static int vm_exec(struct ast_channel *chan, const char *data)
10636 {
10637 int res = 0;
10638 char *tmp;
10639 struct leave_vm_options leave_options;
10640 struct ast_flags flags = { 0 };
10641 char *opts[OPT_ARG_ARRAY_SIZE];
10642 AST_DECLARE_APP_ARGS(args,
10643 AST_APP_ARG(argv0);
10644 AST_APP_ARG(argv1);
10645 );
10646
10647 memset(&leave_options, 0, sizeof(leave_options));
10648
10649 if (chan->_state != AST_STATE_UP)
10650 ast_answer(chan);
10651
10652 if (!ast_strlen_zero(data)) {
10653 tmp = ast_strdupa(data);
10654 AST_STANDARD_APP_ARGS(args, tmp);
10655 if (args.argc == 2) {
10656 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10657 return -1;
10658 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10659 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10660 int gain;
10661
10662 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10663 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10664 return -1;
10665 } else {
10666 leave_options.record_gain = (signed char) gain;
10667 }
10668 }
10669 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10670 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10671 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10672 }
10673 }
10674 } else {
10675 char temp[256];
10676 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10677 if (res < 0)
10678 return res;
10679 if (ast_strlen_zero(temp))
10680 return 0;
10681 args.argv0 = ast_strdupa(temp);
10682 }
10683
10684 res = leave_voicemail(chan, args.argv0, &leave_options);
10685 if (res == 't') {
10686 ast_play_and_wait(chan, "vm-goodbye");
10687 res = 0;
10688 }
10689
10690 if (res == OPERATOR_EXIT) {
10691 res = 0;
10692 }
10693
10694 if (res == ERROR_LOCK_PATH) {
10695 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10696 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10697 res = 0;
10698 }
10699
10700 return res;
10701 }
10702
10703 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10704 {
10705 struct ast_vm_user *vmu;
10706
10707 if (!ast_strlen_zero(box) && box[0] == '*') {
10708 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10709 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10710 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10711 "\n\tand will be ignored.\n", box, context);
10712 return NULL;
10713 }
10714
10715 AST_LIST_TRAVERSE(&users, vmu, list) {
10716 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10717 if (strcasecmp(vmu->context, context)) {
10718 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10719 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10720 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10721 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10722 }
10723 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10724 return NULL;
10725 }
10726 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10727 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10728 return NULL;
10729 }
10730 }
10731
10732 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10733 return NULL;
10734
10735 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10736 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10737
10738 AST_LIST_INSERT_TAIL(&users, vmu, list);
10739
10740 return vmu;
10741 }
10742
10743 static int append_mailbox(const char *context, const char *box, const char *data)
10744 {
10745
10746 char *tmp;
10747 char *stringp;
10748 char *s;
10749 struct ast_vm_user *vmu;
10750 char *mailbox_full;
10751 int new = 0, old = 0, urgent = 0;
10752 char secretfn[PATH_MAX] = "";
10753
10754 tmp = ast_strdupa(data);
10755
10756 if (!(vmu = find_or_create(context, box)))
10757 return -1;
10758
10759 populate_defaults(vmu);
10760
10761 stringp = tmp;
10762 if ((s = strsep(&stringp, ","))) {
10763 if (!ast_strlen_zero(s) && s[0] == '*') {
10764 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10765 "\n\tmust be reset in voicemail.conf.\n", box);
10766 }
10767
10768 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10769 }
10770 if (stringp && (s = strsep(&stringp, ","))) {
10771 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10772 }
10773 if (stringp && (s = strsep(&stringp, ","))) {
10774 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10775 }
10776 if (stringp && (s = strsep(&stringp, ","))) {
10777 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10778 }
10779 if (stringp && (s = strsep(&stringp, ","))) {
10780 apply_options(vmu, s);
10781 }
10782
10783 switch (vmu->passwordlocation) {
10784 case OPT_PWLOC_SPOOLDIR:
10785 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10786 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10787 }
10788
10789 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10790 strcpy(mailbox_full, box);
10791 strcat(mailbox_full, "@");
10792 strcat(mailbox_full, context);
10793
10794 inboxcount2(mailbox_full, &urgent, &new, &old);
10795 queue_mwi_event(mailbox_full, urgent, new, old);
10796
10797 return 0;
10798 }
10799
10800 AST_TEST_DEFINE(test_voicemail_vmuser)
10801 {
10802 int res = 0;
10803 struct ast_vm_user *vmu;
10804
10805 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10806 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10807 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10808 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10809 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10810 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10811 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10812 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10813 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10814 #ifdef IMAP_STORAGE
10815 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10816 "imapfolder=INBOX|imapvmshareid=6000";
10817 #endif
10818
10819 switch (cmd) {
10820 case TEST_INIT:
10821 info->name = "vmuser";
10822 info->category = "/apps/app_voicemail/";
10823 info->summary = "Vmuser unit test";
10824 info->description =
10825 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10826 return AST_TEST_NOT_RUN;
10827 case TEST_EXECUTE:
10828 break;
10829 }
10830
10831 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10832 return AST_TEST_NOT_RUN;
10833 }
10834 ast_set_flag(vmu, VM_ALLOCED);
10835 populate_defaults(vmu);
10836
10837 apply_options(vmu, options_string);
10838
10839 if (!ast_test_flag(vmu, VM_ATTACH)) {
10840 ast_test_status_update(test, "Parse failure for attach option\n");
10841 res = 1;
10842 }
10843 if (strcasecmp(vmu->attachfmt, "wav49")) {
10844 ast_test_status_update(test, "Parse failure for attachftm option\n");
10845 res = 1;
10846 }
10847 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10848 ast_test_status_update(test, "Parse failure for serveremail option\n");
10849 res = 1;
10850 }
10851 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10852 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10853 res = 1;
10854 }
10855 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10856 ast_test_status_update(test, "Parse failure for emailbody option\n");
10857 res = 1;
10858 }
10859 if (strcasecmp(vmu->zonetag, "central")) {
10860 ast_test_status_update(test, "Parse failure for tz option\n");
10861 res = 1;
10862 }
10863 if (!ast_test_flag(vmu, VM_DELETE)) {
10864 ast_test_status_update(test, "Parse failure for delete option\n");
10865 res = 1;
10866 }
10867 if (!ast_test_flag(vmu, VM_SAYCID)) {
10868 ast_test_status_update(test, "Parse failure for saycid option\n");
10869 res = 1;
10870 }
10871 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10872 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10873 res = 1;
10874 }
10875 if (!ast_test_flag(vmu, VM_REVIEW)) {
10876 ast_test_status_update(test, "Parse failure for review option\n");
10877 res = 1;
10878 }
10879 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10880 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10881 res = 1;
10882 }
10883 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10884 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10885 res = 1;
10886 }
10887 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10888 ast_test_status_update(test, "Parse failure for operator option\n");
10889 res = 1;
10890 }
10891 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10892 ast_test_status_update(test, "Parse failure for envelope option\n");
10893 res = 1;
10894 }
10895 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10896 ast_test_status_update(test, "Parse failure for moveheard option\n");
10897 res = 1;
10898 }
10899 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10900 ast_test_status_update(test, "Parse failure for sayduration option\n");
10901 res = 1;
10902 }
10903 if (vmu->saydurationm != 5) {
10904 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10905 res = 1;
10906 }
10907 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10908 ast_test_status_update(test, "Parse failure for forcename option\n");
10909 res = 1;
10910 }
10911 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10912 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10913 res = 1;
10914 }
10915 if (strcasecmp(vmu->callback, "somecontext")) {
10916 ast_test_status_update(test, "Parse failure for callbacks option\n");
10917 res = 1;
10918 }
10919 if (strcasecmp(vmu->dialout, "somecontext2")) {
10920 ast_test_status_update(test, "Parse failure for dialout option\n");
10921 res = 1;
10922 }
10923 if (strcasecmp(vmu->exit, "somecontext3")) {
10924 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10925 res = 1;
10926 }
10927 if (vmu->minsecs != 10) {
10928 ast_test_status_update(test, "Parse failure for minsecs option\n");
10929 res = 1;
10930 }
10931 if (vmu->maxsecs != 100) {
10932 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10933 res = 1;
10934 }
10935 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10936 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10937 res = 1;
10938 }
10939 if (vmu->maxdeletedmsg != 50) {
10940 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10941 res = 1;
10942 }
10943 if (vmu->volgain != 1.3) {
10944 ast_test_status_update(test, "Parse failure for volgain option\n");
10945 res = 1;
10946 }
10947 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10948 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10949 res = 1;
10950 }
10951 #ifdef IMAP_STORAGE
10952 apply_options(vmu, option_string2);
10953
10954 if (strcasecmp(vmu->imapuser, "imapuser")) {
10955 ast_test_status_update(test, "Parse failure for imapuser option\n");
10956 res = 1;
10957 }
10958 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10959 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10960 res = 1;
10961 }
10962 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10963 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10964 res = 1;
10965 }
10966 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10967 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10968 res = 1;
10969 }
10970 #endif
10971
10972 free_user(vmu);
10973 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10974 }
10975
10976 static int vm_box_exists(struct ast_channel *chan, const char *data)
10977 {
10978 struct ast_vm_user svm;
10979 char *context, *box;
10980 AST_DECLARE_APP_ARGS(args,
10981 AST_APP_ARG(mbox);
10982 AST_APP_ARG(options);
10983 );
10984 static int dep_warning = 0;
10985
10986 if (ast_strlen_zero(data)) {
10987 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10988 return -1;
10989 }
10990
10991 if (!dep_warning) {
10992 dep_warning = 1;
10993 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10994 }
10995
10996 box = ast_strdupa(data);
10997
10998 AST_STANDARD_APP_ARGS(args, box);
10999
11000 if (args.options) {
11001 }
11002
11003 if ((context = strchr(args.mbox, '@'))) {
11004 *context = '\0';
11005 context++;
11006 }
11007
11008 if (find_user(&svm, context, args.mbox)) {
11009 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11010 } else
11011 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11012
11013 return 0;
11014 }
11015
11016 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11017 {
11018 struct ast_vm_user svm;
11019 AST_DECLARE_APP_ARGS(arg,
11020 AST_APP_ARG(mbox);
11021 AST_APP_ARG(context);
11022 );
11023
11024 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11025
11026 if (ast_strlen_zero(arg.mbox)) {
11027 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11028 return -1;
11029 }
11030
11031 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11032 return 0;
11033 }
11034
11035 static struct ast_custom_function mailbox_exists_acf = {
11036 .name = "MAILBOX_EXISTS",
11037 .read = acf_mailbox_exists,
11038 };
11039
11040 static int vmauthenticate(struct ast_channel *chan, const char *data)
11041 {
11042 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11043 struct ast_vm_user vmus;
11044 char *options = NULL;
11045 int silent = 0, skipuser = 0;
11046 int res = -1;
11047
11048 if (data) {
11049 s = ast_strdupa(data);
11050 user = strsep(&s, ",");
11051 options = strsep(&s, ",");
11052 if (user) {
11053 s = user;
11054 user = strsep(&s, "@");
11055 context = strsep(&s, "");
11056 if (!ast_strlen_zero(user))
11057 skipuser++;
11058 ast_copy_string(mailbox, user, sizeof(mailbox));
11059 }
11060 }
11061
11062 if (options) {
11063 silent = (strchr(options, 's')) != NULL;
11064 }
11065
11066 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11067 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11068 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11069 ast_play_and_wait(chan, "auth-thankyou");
11070 res = 0;
11071 } else if (mailbox[0] == '*') {
11072
11073 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11074 res = 0;
11075 }
11076 }
11077
11078 return res;
11079 }
11080
11081 static char *show_users_realtime(int fd, const char *context)
11082 {
11083 struct ast_config *cfg;
11084 const char *cat = NULL;
11085
11086 if (!(cfg = ast_load_realtime_multientry("voicemail",
11087 "context", context, SENTINEL))) {
11088 return CLI_FAILURE;
11089 }
11090
11091 ast_cli(fd,
11092 "\n"
11093 "=============================================================\n"
11094 "=== Configured Voicemail Users ==============================\n"
11095 "=============================================================\n"
11096 "===\n");
11097
11098 while ((cat = ast_category_browse(cfg, cat))) {
11099 struct ast_variable *var = NULL;
11100 ast_cli(fd,
11101 "=== Mailbox ...\n"
11102 "===\n");
11103 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11104 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11105 ast_cli(fd,
11106 "===\n"
11107 "=== ---------------------------------------------------------\n"
11108 "===\n");
11109 }
11110
11111 ast_cli(fd,
11112 "=============================================================\n"
11113 "\n");
11114
11115 ast_config_destroy(cfg);
11116
11117 return CLI_SUCCESS;
11118 }
11119
11120 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11121 {
11122 int which = 0;
11123 int wordlen;
11124 struct ast_vm_user *vmu;
11125 const char *context = "";
11126
11127
11128 if (pos > 4)
11129 return NULL;
11130 if (pos == 3)
11131 return (state == 0) ? ast_strdup("for") : NULL;
11132 wordlen = strlen(word);
11133 AST_LIST_TRAVERSE(&users, vmu, list) {
11134 if (!strncasecmp(word, vmu->context, wordlen)) {
11135 if (context && strcmp(context, vmu->context) && ++which > state)
11136 return ast_strdup(vmu->context);
11137
11138 context = vmu->context;
11139 }
11140 }
11141 return NULL;
11142 }
11143
11144
11145 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11146 {
11147 struct ast_vm_user *vmu;
11148 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11149 const char *context = NULL;
11150 int users_counter = 0;
11151
11152 switch (cmd) {
11153 case CLI_INIT:
11154 e->command = "voicemail show users";
11155 e->usage =
11156 "Usage: voicemail show users [for <context>]\n"
11157 " Lists all mailboxes currently set up\n";
11158 return NULL;
11159 case CLI_GENERATE:
11160 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11161 }
11162
11163 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11164 return CLI_SHOWUSAGE;
11165 if (a->argc == 5) {
11166 if (strcmp(a->argv[3],"for"))
11167 return CLI_SHOWUSAGE;
11168 context = a->argv[4];
11169 }
11170
11171 if (ast_check_realtime("voicemail")) {
11172 if (!context) {
11173 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11174 return CLI_SHOWUSAGE;
11175 }
11176 return show_users_realtime(a->fd, context);
11177 }
11178
11179 AST_LIST_LOCK(&users);
11180 if (AST_LIST_EMPTY(&users)) {
11181 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11182 AST_LIST_UNLOCK(&users);
11183 return CLI_FAILURE;
11184 }
11185 if (!context) {
11186 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11187 } else {
11188 int count = 0;
11189 AST_LIST_TRAVERSE(&users, vmu, list) {
11190 if (!strcmp(context, vmu->context)) {
11191 count++;
11192 break;
11193 }
11194 }
11195 if (count) {
11196 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11197 } else {
11198 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11199 AST_LIST_UNLOCK(&users);
11200 return CLI_FAILURE;
11201 }
11202 }
11203 AST_LIST_TRAVERSE(&users, vmu, list) {
11204 int newmsgs = 0, oldmsgs = 0;
11205 char count[12], tmp[256] = "";
11206
11207 if (!context || !strcmp(context, vmu->context)) {
11208 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11209 inboxcount(tmp, &newmsgs, &oldmsgs);
11210 snprintf(count, sizeof(count), "%d", newmsgs);
11211 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11212 users_counter++;
11213 }
11214 }
11215 AST_LIST_UNLOCK(&users);
11216 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11217 return CLI_SUCCESS;
11218 }
11219
11220
11221 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11222 {
11223 struct vm_zone *zone;
11224 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11225 char *res = CLI_SUCCESS;
11226
11227 switch (cmd) {
11228 case CLI_INIT:
11229 e->command = "voicemail show zones";
11230 e->usage =
11231 "Usage: voicemail show zones\n"
11232 " Lists zone message formats\n";
11233 return NULL;
11234 case CLI_GENERATE:
11235 return NULL;
11236 }
11237
11238 if (a->argc != 3)
11239 return CLI_SHOWUSAGE;
11240
11241 AST_LIST_LOCK(&zones);
11242 if (!AST_LIST_EMPTY(&zones)) {
11243 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11244 AST_LIST_TRAVERSE(&zones, zone, list) {
11245 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11246 }
11247 } else {
11248 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11249 res = CLI_FAILURE;
11250 }
11251 AST_LIST_UNLOCK(&zones);
11252
11253 return res;
11254 }
11255
11256
11257 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11258 {
11259 switch (cmd) {
11260 case CLI_INIT:
11261 e->command = "voicemail reload";
11262 e->usage =
11263 "Usage: voicemail reload\n"
11264 " Reload voicemail configuration\n";
11265 return NULL;
11266 case CLI_GENERATE:
11267 return NULL;
11268 }
11269
11270 if (a->argc != 2)
11271 return CLI_SHOWUSAGE;
11272
11273 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11274 load_config(1);
11275
11276 return CLI_SUCCESS;
11277 }
11278
11279 static struct ast_cli_entry cli_voicemail[] = {
11280 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11281 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11282 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11283 };
11284
11285 #ifdef IMAP_STORAGE
11286 #define DATA_EXPORT_VM_USERS(USER) \
11287 USER(ast_vm_user, context, AST_DATA_STRING) \
11288 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11289 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11290 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11291 USER(ast_vm_user, email, AST_DATA_STRING) \
11292 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11293 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11294 USER(ast_vm_user, pager, AST_DATA_STRING) \
11295 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11296 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11297 USER(ast_vm_user, language, AST_DATA_STRING) \
11298 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11299 USER(ast_vm_user, callback, AST_DATA_STRING) \
11300 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11301 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11302 USER(ast_vm_user, exit, AST_DATA_STRING) \
11303 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11304 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11305 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11306 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11307 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11308 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11309 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11310 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11311 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11312 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11313 #else
11314 #define DATA_EXPORT_VM_USERS(USER) \
11315 USER(ast_vm_user, context, AST_DATA_STRING) \
11316 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11317 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11318 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11319 USER(ast_vm_user, email, AST_DATA_STRING) \
11320 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11321 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11322 USER(ast_vm_user, pager, AST_DATA_STRING) \
11323 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11324 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11325 USER(ast_vm_user, language, AST_DATA_STRING) \
11326 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11327 USER(ast_vm_user, callback, AST_DATA_STRING) \
11328 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11329 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11330 USER(ast_vm_user, exit, AST_DATA_STRING) \
11331 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11332 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11333 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11334 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11335 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11336 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11337 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11338 #endif
11339
11340 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11341
11342 #define DATA_EXPORT_VM_ZONES(ZONE) \
11343 ZONE(vm_zone, name, AST_DATA_STRING) \
11344 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11345 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11346
11347 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11348
11349
11350
11351
11352
11353
11354
11355
11356 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11357 struct ast_data *data_root, struct ast_vm_user *user)
11358 {
11359 struct ast_data *data_user, *data_zone;
11360 struct ast_data *data_state;
11361 struct vm_zone *zone = NULL;
11362 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11363 char ext_context[256] = "";
11364
11365 data_user = ast_data_add_node(data_root, "user");
11366 if (!data_user) {
11367 return -1;
11368 }
11369
11370 ast_data_add_structure(ast_vm_user, data_user, user);
11371
11372 AST_LIST_LOCK(&zones);
11373 AST_LIST_TRAVERSE(&zones, zone, list) {
11374 if (!strcmp(zone->name, user->zonetag)) {
11375 break;
11376 }
11377 }
11378 AST_LIST_UNLOCK(&zones);
11379
11380
11381 data_state = ast_data_add_node(data_user, "state");
11382 if (!data_state) {
11383 return -1;
11384 }
11385 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11386 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11387 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11388 ast_data_add_int(data_state, "newmsg", newmsg);
11389 ast_data_add_int(data_state, "oldmsg", oldmsg);
11390
11391 if (zone) {
11392 data_zone = ast_data_add_node(data_user, "zone");
11393 ast_data_add_structure(vm_zone, data_zone, zone);
11394 }
11395
11396 if (!ast_data_search_match(search, data_user)) {
11397 ast_data_remove_node(data_root, data_user);
11398 }
11399
11400 return 0;
11401 }
11402
11403 static int vm_users_data_provider_get(const struct ast_data_search *search,
11404 struct ast_data *data_root)
11405 {
11406 struct ast_vm_user *user;
11407
11408 AST_LIST_LOCK(&users);
11409 AST_LIST_TRAVERSE(&users, user, list) {
11410 vm_users_data_provider_get_helper(search, data_root, user);
11411 }
11412 AST_LIST_UNLOCK(&users);
11413
11414 return 0;
11415 }
11416
11417 static const struct ast_data_handler vm_users_data_provider = {
11418 .version = AST_DATA_HANDLER_VERSION,
11419 .get = vm_users_data_provider_get
11420 };
11421
11422 static const struct ast_data_entry vm_data_providers[] = {
11423 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11424 };
11425
11426 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11427 {
11428 int new = 0, old = 0, urgent = 0;
11429
11430 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11431
11432 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11433 mwi_sub->old_urgent = urgent;
11434 mwi_sub->old_new = new;
11435 mwi_sub->old_old = old;
11436 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11437 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11438 }
11439 }
11440
11441 static void poll_subscribed_mailboxes(void)
11442 {
11443 struct mwi_sub *mwi_sub;
11444
11445 AST_RWLIST_RDLOCK(&mwi_subs);
11446 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11447 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11448 poll_subscribed_mailbox(mwi_sub);
11449 }
11450 }
11451 AST_RWLIST_UNLOCK(&mwi_subs);
11452 }
11453
11454 static void *mb_poll_thread(void *data)
11455 {
11456 while (poll_thread_run) {
11457 struct timespec ts = { 0, };
11458 struct timeval wait;
11459
11460 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11461 ts.tv_sec = wait.tv_sec;
11462 ts.tv_nsec = wait.tv_usec * 1000;
11463
11464 ast_mutex_lock(&poll_lock);
11465 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11466 ast_mutex_unlock(&poll_lock);
11467
11468 if (!poll_thread_run)
11469 break;
11470
11471 poll_subscribed_mailboxes();
11472 }
11473
11474 return NULL;
11475 }
11476
11477 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11478 {
11479 ast_free(mwi_sub);
11480 }
11481
11482 static int handle_unsubscribe(void *datap)
11483 {
11484 struct mwi_sub *mwi_sub;
11485 uint32_t *uniqueid = datap;
11486
11487 AST_RWLIST_WRLOCK(&mwi_subs);
11488 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11489 if (mwi_sub->uniqueid == *uniqueid) {
11490 AST_LIST_REMOVE_CURRENT(entry);
11491 break;
11492 }
11493 }
11494 AST_RWLIST_TRAVERSE_SAFE_END
11495 AST_RWLIST_UNLOCK(&mwi_subs);
11496
11497 if (mwi_sub)
11498 mwi_sub_destroy(mwi_sub);
11499
11500 ast_free(uniqueid);
11501 return 0;
11502 }
11503
11504 static int handle_subscribe(void *datap)
11505 {
11506 unsigned int len;
11507 struct mwi_sub *mwi_sub;
11508 struct mwi_sub_task *p = datap;
11509
11510 len = sizeof(*mwi_sub);
11511 if (!ast_strlen_zero(p->mailbox))
11512 len += strlen(p->mailbox);
11513
11514 if (!ast_strlen_zero(p->context))
11515 len += strlen(p->context) + 1;
11516
11517 if (!(mwi_sub = ast_calloc(1, len)))
11518 return -1;
11519
11520 mwi_sub->uniqueid = p->uniqueid;
11521 if (!ast_strlen_zero(p->mailbox))
11522 strcpy(mwi_sub->mailbox, p->mailbox);
11523
11524 if (!ast_strlen_zero(p->context)) {
11525 strcat(mwi_sub->mailbox, "@");
11526 strcat(mwi_sub->mailbox, p->context);
11527 }
11528
11529 AST_RWLIST_WRLOCK(&mwi_subs);
11530 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11531 AST_RWLIST_UNLOCK(&mwi_subs);
11532 ast_free((void *) p->mailbox);
11533 ast_free((void *) p->context);
11534 ast_free(p);
11535 poll_subscribed_mailbox(mwi_sub);
11536 return 0;
11537 }
11538
11539 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11540 {
11541 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11542
11543 if (!uniqueid) {
11544 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11545 return;
11546 }
11547
11548 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11549 ast_free(uniqueid);
11550 return;
11551 }
11552
11553 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11554 ast_free(uniqueid);
11555 return;
11556 }
11557
11558 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11559 *uniqueid = u;
11560 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11561 ast_free(uniqueid);
11562 }
11563 }
11564
11565 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11566 {
11567 struct mwi_sub_task *mwist;
11568
11569 if (ast_event_get_type(event) != AST_EVENT_SUB)
11570 return;
11571
11572 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11573 return;
11574
11575 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11576 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11577 return;
11578 }
11579 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11580 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11581 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11582
11583 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11584 ast_free(mwist);
11585 }
11586 }
11587
11588 static void start_poll_thread(void)
11589 {
11590 int errcode;
11591 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11592 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11593 AST_EVENT_IE_END);
11594
11595 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11596 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11597 AST_EVENT_IE_END);
11598
11599 if (mwi_sub_sub)
11600 ast_event_report_subs(mwi_sub_sub);
11601
11602 poll_thread_run = 1;
11603
11604 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11605 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11606 }
11607 }
11608
11609 static void stop_poll_thread(void)
11610 {
11611 poll_thread_run = 0;
11612
11613 if (mwi_sub_sub) {
11614 ast_event_unsubscribe(mwi_sub_sub);
11615 mwi_sub_sub = NULL;
11616 }
11617
11618 if (mwi_unsub_sub) {
11619 ast_event_unsubscribe(mwi_unsub_sub);
11620 mwi_unsub_sub = NULL;
11621 }
11622
11623 ast_mutex_lock(&poll_lock);
11624 ast_cond_signal(&poll_cond);
11625 ast_mutex_unlock(&poll_lock);
11626
11627 pthread_join(poll_thread, NULL);
11628
11629 poll_thread = AST_PTHREADT_NULL;
11630 }
11631
11632
11633 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11634 {
11635 struct ast_vm_user *vmu = NULL;
11636 const char *id = astman_get_header(m, "ActionID");
11637 char actionid[128] = "";
11638
11639 if (!ast_strlen_zero(id))
11640 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11641
11642 AST_LIST_LOCK(&users);
11643
11644 if (AST_LIST_EMPTY(&users)) {
11645 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11646 AST_LIST_UNLOCK(&users);
11647 return RESULT_SUCCESS;
11648 }
11649
11650 astman_send_ack(s, m, "Voicemail user list will follow");
11651
11652 AST_LIST_TRAVERSE(&users, vmu, list) {
11653 char dirname[256];
11654
11655 #ifdef IMAP_STORAGE
11656 int new, old;
11657 inboxcount(vmu->mailbox, &new, &old);
11658 #endif
11659
11660 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11661 astman_append(s,
11662 "%s"
11663 "Event: VoicemailUserEntry\r\n"
11664 "VMContext: %s\r\n"
11665 "VoiceMailbox: %s\r\n"
11666 "Fullname: %s\r\n"
11667 "Email: %s\r\n"
11668 "Pager: %s\r\n"
11669 "ServerEmail: %s\r\n"
11670 "MailCommand: %s\r\n"
11671 "Language: %s\r\n"
11672 "TimeZone: %s\r\n"
11673 "Callback: %s\r\n"
11674 "Dialout: %s\r\n"
11675 "UniqueID: %s\r\n"
11676 "ExitContext: %s\r\n"
11677 "SayDurationMinimum: %d\r\n"
11678 "SayEnvelope: %s\r\n"
11679 "SayCID: %s\r\n"
11680 "AttachMessage: %s\r\n"
11681 "AttachmentFormat: %s\r\n"
11682 "DeleteMessage: %s\r\n"
11683 "VolumeGain: %.2f\r\n"
11684 "CanReview: %s\r\n"
11685 "CallOperator: %s\r\n"
11686 "MaxMessageCount: %d\r\n"
11687 "MaxMessageLength: %d\r\n"
11688 "NewMessageCount: %d\r\n"
11689 #ifdef IMAP_STORAGE
11690 "OldMessageCount: %d\r\n"
11691 "IMAPUser: %s\r\n"
11692 #endif
11693 "\r\n",
11694 actionid,
11695 vmu->context,
11696 vmu->mailbox,
11697 vmu->fullname,
11698 vmu->email,
11699 vmu->pager,
11700 vmu->serveremail,
11701 vmu->mailcmd,
11702 vmu->language,
11703 vmu->zonetag,
11704 vmu->callback,
11705 vmu->dialout,
11706 vmu->uniqueid,
11707 vmu->exit,
11708 vmu->saydurationm,
11709 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11710 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11711 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11712 vmu->attachfmt,
11713 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11714 vmu->volgain,
11715 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11716 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11717 vmu->maxmsg,
11718 vmu->maxsecs,
11719 #ifdef IMAP_STORAGE
11720 new, old, vmu->imapuser
11721 #else
11722 count_messages(vmu, dirname)
11723 #endif
11724 );
11725 }
11726 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11727
11728 AST_LIST_UNLOCK(&users);
11729
11730 return RESULT_SUCCESS;
11731 }
11732
11733
11734 static void free_vm_users(void)
11735 {
11736 struct ast_vm_user *current;
11737 AST_LIST_LOCK(&users);
11738 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11739 ast_set_flag(current, VM_ALLOCED);
11740 free_user(current);
11741 }
11742 AST_LIST_UNLOCK(&users);
11743 }
11744
11745
11746 static void free_vm_zones(void)
11747 {
11748 struct vm_zone *zcur;
11749 AST_LIST_LOCK(&zones);
11750 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11751 free_zone(zcur);
11752 AST_LIST_UNLOCK(&zones);
11753 }
11754
11755 static const char *substitute_escapes(const char *value)
11756 {
11757 char *current;
11758
11759
11760 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11761
11762 ast_str_reset(str);
11763
11764
11765 for (current = (char *) value; *current; current++) {
11766 if (*current == '\\') {
11767 current++;
11768 if (!*current) {
11769 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11770 break;
11771 }
11772 switch (*current) {
11773 case '\\':
11774 ast_str_append(&str, 0, "\\");
11775 break;
11776 case 'r':
11777 ast_str_append(&str, 0, "\r");
11778 break;
11779 case 'n':
11780 #ifdef IMAP_STORAGE
11781 if (!str->used || str->str[str->used - 1] != '\r') {
11782 ast_str_append(&str, 0, "\r");
11783 }
11784 #endif
11785 ast_str_append(&str, 0, "\n");
11786 break;
11787 case 't':
11788 ast_str_append(&str, 0, "\t");
11789 break;
11790 default:
11791 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11792 break;
11793 }
11794 } else {
11795 ast_str_append(&str, 0, "%c", *current);
11796 }
11797 }
11798
11799 return ast_str_buffer(str);
11800 }
11801
11802 static int load_config(int reload)
11803 {
11804 struct ast_config *cfg, *ucfg;
11805 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11806 int res;
11807
11808 ast_unload_realtime("voicemail");
11809 ast_unload_realtime("voicemail_data");
11810
11811 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11812 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11813 return 0;
11814 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11815 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11816 ucfg = NULL;
11817 }
11818 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11819 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11820 ast_config_destroy(ucfg);
11821 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11822 return 0;
11823 }
11824 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11825 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11826 return 0;
11827 } else {
11828 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11829 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11830 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11831 ucfg = NULL;
11832 }
11833 }
11834
11835 res = actual_load_config(reload, cfg, ucfg);
11836
11837 ast_config_destroy(cfg);
11838 ast_config_destroy(ucfg);
11839
11840 return res;
11841 }
11842
11843 #ifdef TEST_FRAMEWORK
11844 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11845 {
11846 ast_unload_realtime("voicemail");
11847 ast_unload_realtime("voicemail_data");
11848 return actual_load_config(reload, cfg, ucfg);
11849 }
11850 #endif
11851
11852 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11853 {
11854 struct ast_vm_user *current;
11855 char *cat;
11856 struct ast_variable *var;
11857 const char *val;
11858 char *q, *stringp, *tmp;
11859 int x;
11860 int tmpadsi[4];
11861 char secretfn[PATH_MAX] = "";
11862
11863 #ifdef IMAP_STORAGE
11864 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11865 #endif
11866
11867 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11868 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11869 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11870 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11871 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11872
11873
11874 free_vm_users();
11875
11876
11877 free_vm_zones();
11878
11879 AST_LIST_LOCK(&users);
11880
11881 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11882 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11883
11884 if (cfg) {
11885
11886
11887 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11888 val = "default";
11889 ast_copy_string(userscontext, val, sizeof(userscontext));
11890
11891 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11892 val = "yes";
11893 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11894
11895 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11896 val = "no";
11897 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11898
11899 volgain = 0.0;
11900 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11901 sscanf(val, "%30lf", &volgain);
11902
11903 #ifdef ODBC_STORAGE
11904 strcpy(odbc_database, "asterisk");
11905 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11906 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11907 }
11908 strcpy(odbc_table, "voicemessages");
11909 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11910 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11911 }
11912 #endif
11913
11914 strcpy(mailcmd, SENDMAIL);
11915 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11916 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11917
11918 maxsilence = 0;
11919 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11920 maxsilence = atoi(val);
11921 if (maxsilence > 0)
11922 maxsilence *= 1000;
11923 }
11924
11925 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11926 maxmsg = MAXMSG;
11927 } else {
11928 maxmsg = atoi(val);
11929 if (maxmsg < 0) {
11930 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11931 maxmsg = MAXMSG;
11932 } else if (maxmsg > MAXMSGLIMIT) {
11933 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11934 maxmsg = MAXMSGLIMIT;
11935 }
11936 }
11937
11938 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11939 maxdeletedmsg = 0;
11940 } else {
11941 if (sscanf(val, "%30d", &x) == 1)
11942 maxdeletedmsg = x;
11943 else if (ast_true(val))
11944 maxdeletedmsg = MAXMSG;
11945 else
11946 maxdeletedmsg = 0;
11947
11948 if (maxdeletedmsg < 0) {
11949 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11950 maxdeletedmsg = MAXMSG;
11951 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11952 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11953 maxdeletedmsg = MAXMSGLIMIT;
11954 }
11955 }
11956
11957
11958 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11959 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11960 }
11961
11962
11963 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11964 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11965 }
11966
11967
11968 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11969 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11970 pwdchange = PWDCHANGE_EXTERNAL;
11971 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11972 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11973 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11974 }
11975
11976
11977 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11978 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11979 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11980 }
11981
11982 #ifdef IMAP_STORAGE
11983
11984 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11985 ast_copy_string(imapserver, val, sizeof(imapserver));
11986 } else {
11987 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11988 }
11989
11990 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11991 ast_copy_string(imapport, val, sizeof(imapport));
11992 } else {
11993 ast_copy_string(imapport, "143", sizeof(imapport));
11994 }
11995
11996 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11997 ast_copy_string(imapflags, val, sizeof(imapflags));
11998 }
11999
12000 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12001 ast_copy_string(authuser, val, sizeof(authuser));
12002 }
12003
12004 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12005 ast_copy_string(authpassword, val, sizeof(authpassword));
12006 }
12007
12008 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12009 if (ast_false(val))
12010 expungeonhangup = 0;
12011 else
12012 expungeonhangup = 1;
12013 } else {
12014 expungeonhangup = 1;
12015 }
12016
12017 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12018 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12019 } else {
12020 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12021 }
12022 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12023 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12024 }
12025 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12026 imapgreetings = ast_true(val);
12027 } else {
12028 imapgreetings = 0;
12029 }
12030 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12031 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12032 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12033
12034 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12035 } else {
12036 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12037 }
12038
12039
12040
12041
12042
12043 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12044 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12045 } else {
12046 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12047 }
12048
12049 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12050 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12051 } else {
12052 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12053 }
12054
12055 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12056 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12057 } else {
12058 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12059 }
12060
12061 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12062 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12063 } else {
12064 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12065 }
12066
12067
12068 imapversion++;
12069 #endif
12070
12071 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12072 ast_copy_string(externnotify, val, sizeof(externnotify));
12073 ast_debug(1, "found externnotify: %s\n", externnotify);
12074 } else {
12075 externnotify[0] = '\0';
12076 }
12077
12078
12079 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12080 ast_debug(1, "Enabled SMDI voicemail notification\n");
12081 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12082 smdi_iface = ast_smdi_interface_find(val);
12083 } else {
12084 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12085 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12086 }
12087 if (!smdi_iface) {
12088 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12089 }
12090 }
12091
12092
12093 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12094 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12095 silencethreshold = atoi(val);
12096
12097 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12098 val = ASTERISK_USERNAME;
12099 ast_copy_string(serveremail, val, sizeof(serveremail));
12100
12101 vmmaxsecs = 0;
12102 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12103 if (sscanf(val, "%30d", &x) == 1) {
12104 vmmaxsecs = x;
12105 } else {
12106 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12107 }
12108 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12109 static int maxmessage_deprecate = 0;
12110 if (maxmessage_deprecate == 0) {
12111 maxmessage_deprecate = 1;
12112 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12113 }
12114 if (sscanf(val, "%30d", &x) == 1) {
12115 vmmaxsecs = x;
12116 } else {
12117 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12118 }
12119 }
12120
12121 vmminsecs = 0;
12122 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12123 if (sscanf(val, "%30d", &x) == 1) {
12124 vmminsecs = x;
12125 if (maxsilence / 1000 >= vmminsecs) {
12126 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12127 }
12128 } else {
12129 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12130 }
12131 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12132 static int maxmessage_deprecate = 0;
12133 if (maxmessage_deprecate == 0) {
12134 maxmessage_deprecate = 1;
12135 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12136 }
12137 if (sscanf(val, "%30d", &x) == 1) {
12138 vmminsecs = x;
12139 if (maxsilence / 1000 >= vmminsecs) {
12140 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12141 }
12142 } else {
12143 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12144 }
12145 }
12146
12147 val = ast_variable_retrieve(cfg, "general", "format");
12148 if (!val) {
12149 val = "wav";
12150 } else {
12151 tmp = ast_strdupa(val);
12152 val = ast_format_str_reduce(tmp);
12153 if (!val) {
12154 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12155 val = "wav";
12156 }
12157 }
12158 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12159
12160 skipms = 3000;
12161 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12162 if (sscanf(val, "%30d", &x) == 1) {
12163 maxgreet = x;
12164 } else {
12165 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12166 }
12167 }
12168
12169 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12170 if (sscanf(val, "%30d", &x) == 1) {
12171 skipms = x;
12172 } else {
12173 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12174 }
12175 }
12176
12177 maxlogins = 3;
12178 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12179 if (sscanf(val, "%30d", &x) == 1) {
12180 maxlogins = x;
12181 } else {
12182 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12183 }
12184 }
12185
12186 minpassword = MINPASSWORD;
12187 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12188 if (sscanf(val, "%30d", &x) == 1) {
12189 minpassword = x;
12190 } else {
12191 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12192 }
12193 }
12194
12195
12196 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12197 val = "no";
12198 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12199
12200
12201 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12202 val = "no";
12203 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12204
12205 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12206 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12207 stringp = ast_strdupa(val);
12208 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12209 if (!ast_strlen_zero(stringp)) {
12210 q = strsep(&stringp, ",");
12211 while ((*q == ' ')||(*q == '\t'))
12212 q++;
12213 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12214 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12215 } else {
12216 cidinternalcontexts[x][0] = '\0';
12217 }
12218 }
12219 }
12220 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12221 ast_debug(1, "VM Review Option disabled globally\n");
12222 val = "no";
12223 }
12224 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12225
12226
12227 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12228 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12229 val = "no";
12230 } else {
12231 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12232 }
12233 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12234 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12235 ast_debug(1, "VM next message wrap disabled globally\n");
12236 val = "no";
12237 }
12238 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12239
12240 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12241 ast_debug(1, "VM Operator break disabled globally\n");
12242 val = "no";
12243 }
12244 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12245
12246 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12247 ast_debug(1, "VM CID Info before msg disabled globally\n");
12248 val = "no";
12249 }
12250 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12251
12252 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12253 ast_debug(1, "Send Voicemail msg disabled globally\n");
12254 val = "no";
12255 }
12256 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12257
12258 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12259 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12260 val = "yes";
12261 }
12262 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12263
12264 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12265 ast_debug(1, "Move Heard enabled globally\n");
12266 val = "yes";
12267 }
12268 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12269
12270 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12271 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12272 val = "no";
12273 }
12274 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12275
12276 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12277 ast_debug(1, "Duration info before msg enabled globally\n");
12278 val = "yes";
12279 }
12280 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12281
12282 saydurationminfo = 2;
12283 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12284 if (sscanf(val, "%30d", &x) == 1) {
12285 saydurationminfo = x;
12286 } else {
12287 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12288 }
12289 }
12290
12291 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12292 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12293 val = "no";
12294 }
12295 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12296
12297 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12298 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12299 ast_debug(1, "found dialout context: %s\n", dialcontext);
12300 } else {
12301 dialcontext[0] = '\0';
12302 }
12303
12304 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12305 ast_copy_string(callcontext, val, sizeof(callcontext));
12306 ast_debug(1, "found callback context: %s\n", callcontext);
12307 } else {
12308 callcontext[0] = '\0';
12309 }
12310
12311 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12312 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12313 ast_debug(1, "found operator context: %s\n", exitcontext);
12314 } else {
12315 exitcontext[0] = '\0';
12316 }
12317
12318
12319 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12320 ast_copy_string(vm_password, val, sizeof(vm_password));
12321 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12322 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12323 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12324 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12325 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12326 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12327 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12328 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12329 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12330 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12331 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12332 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12333 }
12334 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12335 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12336 }
12337
12338 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12339 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12340 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12341 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12342 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12343 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12344 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12345 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12346 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12347 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12348
12349 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12350 val = "no";
12351 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12352
12353 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12354 val = "voicemail.conf";
12355 }
12356 if (!(strcmp(val, "spooldir"))) {
12357 passwordlocation = OPT_PWLOC_SPOOLDIR;
12358 } else {
12359 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12360 }
12361
12362 poll_freq = DEFAULT_POLL_FREQ;
12363 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12364 if (sscanf(val, "%30u", &poll_freq) != 1) {
12365 poll_freq = DEFAULT_POLL_FREQ;
12366 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12367 }
12368 }
12369
12370 poll_mailboxes = 0;
12371 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12372 poll_mailboxes = ast_true(val);
12373
12374 memset(fromstring, 0, sizeof(fromstring));
12375 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12376 strcpy(charset, "ISO-8859-1");
12377 if (emailbody) {
12378 ast_free(emailbody);
12379 emailbody = NULL;
12380 }
12381 if (emailsubject) {
12382 ast_free(emailsubject);
12383 emailsubject = NULL;
12384 }
12385 if (pagerbody) {
12386 ast_free(pagerbody);
12387 pagerbody = NULL;
12388 }
12389 if (pagersubject) {
12390 ast_free(pagersubject);
12391 pagersubject = NULL;
12392 }
12393 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12394 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12395 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12396 ast_copy_string(fromstring, val, sizeof(fromstring));
12397 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12398 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12399 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12400 ast_copy_string(charset, val, sizeof(charset));
12401 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12402 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12403 for (x = 0; x < 4; x++) {
12404 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12405 }
12406 }
12407 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12408 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12409 for (x = 0; x < 4; x++) {
12410 memcpy(&adsisec[x], &tmpadsi[x], 1);
12411 }
12412 }
12413 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12414 if (atoi(val)) {
12415 adsiver = atoi(val);
12416 }
12417 }
12418 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12419 ast_copy_string(zonetag, val, sizeof(zonetag));
12420 }
12421 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12422 ast_copy_string(locale, val, sizeof(locale));
12423 }
12424 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12425 emailsubject = ast_strdup(substitute_escapes(val));
12426 }
12427 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12428 emailbody = ast_strdup(substitute_escapes(val));
12429 }
12430 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12431 pagersubject = ast_strdup(substitute_escapes(val));
12432 }
12433 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12434 pagerbody = ast_strdup(substitute_escapes(val));
12435 }
12436
12437
12438 if (ucfg) {
12439 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12440 if (!strcasecmp(cat, "general")) {
12441 continue;
12442 }
12443 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12444 continue;
12445 if ((current = find_or_create(userscontext, cat))) {
12446 populate_defaults(current);
12447 apply_options_full(current, ast_variable_browse(ucfg, cat));
12448 ast_copy_string(current->context, userscontext, sizeof(current->context));
12449 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12450 current->passwordlocation = OPT_PWLOC_USERSCONF;
12451 }
12452
12453 switch (current->passwordlocation) {
12454 case OPT_PWLOC_SPOOLDIR:
12455 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12456 read_password_from_file(secretfn, current->password, sizeof(current->password));
12457 }
12458 }
12459 }
12460 }
12461
12462
12463 cat = ast_category_browse(cfg, NULL);
12464 while (cat) {
12465 if (strcasecmp(cat, "general")) {
12466 var = ast_variable_browse(cfg, cat);
12467 if (strcasecmp(cat, "zonemessages")) {
12468
12469 while (var) {
12470 append_mailbox(cat, var->name, var->value);
12471 var = var->next;
12472 }
12473 } else {
12474
12475 while (var) {
12476 struct vm_zone *z;
12477 if ((z = ast_malloc(sizeof(*z)))) {
12478 char *msg_format, *tzone;
12479 msg_format = ast_strdupa(var->value);
12480 tzone = strsep(&msg_format, "|,");
12481 if (msg_format) {
12482 ast_copy_string(z->name, var->name, sizeof(z->name));
12483 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12484 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12485 AST_LIST_LOCK(&zones);
12486 AST_LIST_INSERT_HEAD(&zones, z, list);
12487 AST_LIST_UNLOCK(&zones);
12488 } else {
12489 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12490 ast_free(z);
12491 }
12492 } else {
12493 AST_LIST_UNLOCK(&users);
12494 return -1;
12495 }
12496 var = var->next;
12497 }
12498 }
12499 }
12500 cat = ast_category_browse(cfg, cat);
12501 }
12502
12503 AST_LIST_UNLOCK(&users);
12504
12505 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12506 start_poll_thread();
12507 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12508 stop_poll_thread();;
12509
12510 return 0;
12511 } else {
12512 AST_LIST_UNLOCK(&users);
12513 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12514 return 0;
12515 }
12516 }
12517
12518 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12519 {
12520 int res = -1;
12521 char dir[PATH_MAX];
12522 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12523 ast_debug(2, "About to try retrieving name file %s\n", dir);
12524 RETRIEVE(dir, -1, mailbox, context);
12525 if (ast_fileexists(dir, NULL, NULL)) {
12526 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12527 }
12528 DISPOSE(dir, -1);
12529 return res;
12530 }
12531
12532 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12533 struct ast_config *pwconf;
12534 struct ast_flags config_flags = { 0 };
12535
12536 pwconf = ast_config_load(secretfn, config_flags);
12537 if (pwconf) {
12538 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12539 if (val) {
12540 ast_copy_string(password, val, passwordlen);
12541 ast_config_destroy(pwconf);
12542 return;
12543 }
12544 ast_config_destroy(pwconf);
12545 }
12546 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12547 }
12548
12549 static int write_password_to_file(const char *secretfn, const char *password) {
12550 struct ast_config *conf;
12551 struct ast_category *cat;
12552 struct ast_variable *var;
12553 int res = -1;
12554
12555 if (!(conf = ast_config_new())) {
12556 ast_log(LOG_ERROR, "Error creating new config structure\n");
12557 return res;
12558 }
12559 if (!(cat = ast_category_new("general", "", 1))) {
12560 ast_log(LOG_ERROR, "Error creating new category structure\n");
12561 ast_config_destroy(conf);
12562 return res;
12563 }
12564 if (!(var = ast_variable_new("password", password, ""))) {
12565 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12566 ast_config_destroy(conf);
12567 ast_category_destroy(cat);
12568 return res;
12569 }
12570 ast_category_append(conf, cat);
12571 ast_variable_append(cat, var);
12572 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12573 res = 0;
12574 } else {
12575 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12576 }
12577
12578 ast_config_destroy(conf);
12579 return res;
12580 }
12581
12582 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12583 {
12584 char *context;
12585 char *args_copy;
12586 int res;
12587
12588 if (ast_strlen_zero(data)) {
12589 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12590 return -1;
12591 }
12592
12593 args_copy = ast_strdupa(data);
12594 if ((context = strchr(args_copy, '@'))) {
12595 *context++ = '\0';
12596 } else {
12597 context = "default";
12598 }
12599
12600 if ((res = sayname(chan, args_copy, context) < 0)) {
12601 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12602 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12603 if (!res) {
12604 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12605 }
12606 }
12607
12608 return res;
12609 }
12610
12611 #ifdef TEST_FRAMEWORK
12612 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12613 {
12614 return 0;
12615 }
12616
12617 static struct ast_frame *fake_read(struct ast_channel *ast)
12618 {
12619 return &ast_null_frame;
12620 }
12621
12622 AST_TEST_DEFINE(test_voicemail_vmsayname)
12623 {
12624 char dir[PATH_MAX];
12625 char dir2[PATH_MAX];
12626 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12627 static const char TEST_EXTENSION[] = "1234";
12628
12629 struct ast_channel *test_channel1 = NULL;
12630 int res = -1;
12631
12632 static const struct ast_channel_tech fake_tech = {
12633 .write = fake_write,
12634 .read = fake_read,
12635 };
12636
12637 switch (cmd) {
12638 case TEST_INIT:
12639 info->name = "vmsayname_exec";
12640 info->category = "/apps/app_voicemail/";
12641 info->summary = "Vmsayname unit test";
12642 info->description =
12643 "This tests passing various parameters to vmsayname";
12644 return AST_TEST_NOT_RUN;
12645 case TEST_EXECUTE:
12646 break;
12647 }
12648
12649 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12650 NULL, NULL, 0, 0, "TestChannel1"))) {
12651 goto exit_vmsayname_test;
12652 }
12653
12654
12655 test_channel1->nativeformats = AST_FORMAT_GSM;
12656 test_channel1->writeformat = AST_FORMAT_GSM;
12657 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12658 test_channel1->readformat = AST_FORMAT_GSM;
12659 test_channel1->rawreadformat = AST_FORMAT_GSM;
12660 test_channel1->tech = &fake_tech;
12661
12662 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12663 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12664 if (!(res = vmsayname_exec(test_channel1, dir))) {
12665 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12666 if (ast_fileexists(dir, NULL, NULL)) {
12667 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12668 res = -1;
12669 goto exit_vmsayname_test;
12670 } else {
12671
12672 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12673 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12674 goto exit_vmsayname_test;
12675 }
12676 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12677 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12678
12679 if ((res = symlink(dir, dir2))) {
12680 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12681 goto exit_vmsayname_test;
12682 }
12683 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12684 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12685 res = vmsayname_exec(test_channel1, dir);
12686
12687
12688 unlink(dir2);
12689 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12690 rmdir(dir2);
12691 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12692 rmdir(dir2);
12693 }
12694 }
12695
12696 exit_vmsayname_test:
12697
12698 if (test_channel1) {
12699 ast_hangup(test_channel1);
12700 }
12701
12702 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12703 }
12704
12705 AST_TEST_DEFINE(test_voicemail_msgcount)
12706 {
12707 int i, j, res = AST_TEST_PASS, syserr;
12708 struct ast_vm_user *vmu;
12709 struct vm_state vms;
12710 #ifdef IMAP_STORAGE
12711 struct ast_channel *chan = NULL;
12712 #endif
12713 struct {
12714 char dir[256];
12715 char file[256];
12716 char txtfile[256];
12717 } tmp[3];
12718 char syscmd[256];
12719 const char origweasels[] = "tt-weasels";
12720 const char testcontext[] = "test";
12721 const char testmailbox[] = "00000000";
12722 const char testspec[] = "00000000@test";
12723 FILE *txt;
12724 int new, old, urgent;
12725 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12726 const int folder2mbox[3] = { 1, 11, 0 };
12727 const int expected_results[3][12] = {
12728
12729 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12730 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12731 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12732 };
12733
12734 switch (cmd) {
12735 case TEST_INIT:
12736 info->name = "test_voicemail_msgcount";
12737 info->category = "/apps/app_voicemail/";
12738 info->summary = "Test Voicemail status checks";
12739 info->description =
12740 "Verify that message counts are correct when retrieved through the public API";
12741 return AST_TEST_NOT_RUN;
12742 case TEST_EXECUTE:
12743 break;
12744 }
12745
12746
12747 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12748 if ((syserr = ast_safe_system(syscmd))) {
12749 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12750 syserr > 0 ? strerror(syserr) : "unable to fork()");
12751 return AST_TEST_FAIL;
12752 }
12753
12754 #ifdef IMAP_STORAGE
12755 if (!(chan = ast_dummy_channel_alloc())) {
12756 ast_test_status_update(test, "Unable to create dummy channel\n");
12757 return AST_TEST_FAIL;
12758 }
12759 #endif
12760
12761 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12762 !(vmu = find_or_create(testcontext, testmailbox))) {
12763 ast_test_status_update(test, "Cannot create vmu structure\n");
12764 ast_unreplace_sigchld();
12765 #ifdef IMAP_STORAGE
12766 chan = ast_channel_unref(chan);
12767 #endif
12768 return AST_TEST_FAIL;
12769 }
12770
12771 populate_defaults(vmu);
12772 memset(&vms, 0, sizeof(vms));
12773
12774
12775 for (i = 0; i < 3; i++) {
12776 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12777 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12778 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12779
12780 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12781 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12782 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12783 if ((syserr = ast_safe_system(syscmd))) {
12784 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12785 syserr > 0 ? strerror(syserr) : "unable to fork()");
12786 ast_unreplace_sigchld();
12787 #ifdef IMAP_STORAGE
12788 chan = ast_channel_unref(chan);
12789 #endif
12790 return AST_TEST_FAIL;
12791 }
12792 }
12793
12794 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12795 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12796 fclose(txt);
12797 } else {
12798 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12799 res = AST_TEST_FAIL;
12800 break;
12801 }
12802 open_mailbox(&vms, vmu, folder2mbox[i]);
12803 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12804
12805
12806 for (j = 0; j < 3; j++) {
12807
12808 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12809 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12810 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12811 res = AST_TEST_FAIL;
12812 }
12813 }
12814
12815 new = old = urgent = 0;
12816 if (ast_app_inboxcount(testspec, &new, &old)) {
12817 ast_test_status_update(test, "inboxcount returned failure\n");
12818 res = AST_TEST_FAIL;
12819 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12820 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12821 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12822 res = AST_TEST_FAIL;
12823 }
12824
12825 new = old = urgent = 0;
12826 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12827 ast_test_status_update(test, "inboxcount2 returned failure\n");
12828 res = AST_TEST_FAIL;
12829 } else if (old != expected_results[i][6 + 0] ||
12830 urgent != expected_results[i][6 + 1] ||
12831 new != expected_results[i][6 + 2] ) {
12832 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12833 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12834 res = AST_TEST_FAIL;
12835 }
12836
12837 new = old = urgent = 0;
12838 for (j = 0; j < 3; j++) {
12839 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12840 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12841 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12842 res = AST_TEST_FAIL;
12843 }
12844 }
12845 }
12846
12847 for (i = 0; i < 3; i++) {
12848
12849
12850
12851 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12852 DISPOSE(tmp[i].dir, 0);
12853 }
12854
12855 if (vms.deleted) {
12856 ast_free(vms.deleted);
12857 }
12858 if (vms.heard) {
12859 ast_free(vms.heard);
12860 }
12861
12862 #ifdef IMAP_STORAGE
12863 chan = ast_channel_unref(chan);
12864 #endif
12865
12866
12867 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12868 if ((syserr = ast_safe_system(syscmd))) {
12869 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12870 syserr > 0 ? strerror(syserr) : "unable to fork()");
12871 }
12872
12873 return res;
12874 }
12875
12876 AST_TEST_DEFINE(test_voicemail_notify_endl)
12877 {
12878 int res = AST_TEST_PASS;
12879 char testcontext[] = "test";
12880 char testmailbox[] = "00000000";
12881 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12882 char attach[256], attach2[256];
12883 char buf[256] = "";
12884 struct ast_channel *chan = NULL;
12885 struct ast_vm_user *vmu, vmus = {
12886 .flags = 0,
12887 };
12888 FILE *file;
12889 struct {
12890 char *name;
12891 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12892 void *location;
12893 union {
12894 int intval;
12895 char *strval;
12896 } u;
12897 } test_items[] = {
12898 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12899 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12900 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12901 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12902 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12903 { "attach2", STRPTR, attach2, .u.strval = "" },
12904 { "attach", STRPTR, attach, .u.strval = "" },
12905 };
12906 int which;
12907
12908 switch (cmd) {
12909 case TEST_INIT:
12910 info->name = "test_voicemail_notify_endl";
12911 info->category = "/apps/app_voicemail/";
12912 info->summary = "Test Voicemail notification end-of-line";
12913 info->description =
12914 "Verify that notification emails use a consistent end-of-line character";
12915 return AST_TEST_NOT_RUN;
12916 case TEST_EXECUTE:
12917 break;
12918 }
12919
12920 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12921 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12922
12923 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12924 !(vmu = find_or_create(testcontext, testmailbox))) {
12925 ast_test_status_update(test, "Cannot create vmu structure\n");
12926 return AST_TEST_NOT_RUN;
12927 }
12928
12929 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12930 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12931 return AST_TEST_NOT_RUN;
12932 }
12933
12934 populate_defaults(vmu);
12935 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12936 #ifdef IMAP_STORAGE
12937
12938 #endif
12939
12940 file = tmpfile();
12941 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12942
12943 rewind(file);
12944 if (ftruncate(fileno(file), 0)) {
12945 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12946 res = AST_TEST_FAIL;
12947 break;
12948 }
12949
12950
12951 if (test_items[which].type == INT) {
12952 *((int *) test_items[which].location) = test_items[which].u.intval;
12953 } else if (test_items[which].type == FLAGVAL) {
12954 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12955 ast_clear_flag(vmu, test_items[which].u.intval);
12956 } else {
12957 ast_set_flag(vmu, test_items[which].u.intval);
12958 }
12959 } else if (test_items[which].type == STATIC) {
12960 strcpy(test_items[which].location, test_items[which].u.strval);
12961 } else if (test_items[which].type == STRPTR) {
12962 test_items[which].location = test_items[which].u.strval;
12963 }
12964
12965 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12966 rewind(file);
12967 while (fgets(buf, sizeof(buf), file)) {
12968 if (
12969 #ifdef IMAP_STORAGE
12970 buf[strlen(buf) - 2] != '\r'
12971 #else
12972 buf[strlen(buf) - 2] == '\r'
12973 #endif
12974 || buf[strlen(buf) - 1] != '\n') {
12975 res = AST_TEST_FAIL;
12976 }
12977 }
12978 }
12979 fclose(file);
12980 return res;
12981 }
12982
12983 AST_TEST_DEFINE(test_voicemail_load_config)
12984 {
12985 int res = AST_TEST_PASS;
12986 struct ast_vm_user *vmu;
12987 struct ast_config *cfg;
12988 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
12989 int fd;
12990 FILE *file;
12991 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
12992
12993 switch (cmd) {
12994 case TEST_INIT:
12995 info->name = "test_voicemail_load_config";
12996 info->category = "/apps/app_voicemail/";
12997 info->summary = "Test loading Voicemail config";
12998 info->description =
12999 "Verify that configuration is loaded consistently. "
13000 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13001 "some options were loaded after the mailboxes were instantiated, causing "
13002 "those options not to be set correctly.";
13003 return AST_TEST_NOT_RUN;
13004 case TEST_EXECUTE:
13005 break;
13006 }
13007
13008
13009 if ((fd = mkstemp(config_filename)) < 0) {
13010 return AST_TEST_FAIL;
13011 }
13012 if (!(file = fdopen(fd, "w"))) {
13013 close(fd);
13014 unlink(config_filename);
13015 return AST_TEST_FAIL;
13016 }
13017 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13018 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13019 fputs("00000002 => 9999,Mrs. Test\n", file);
13020 fclose(file);
13021
13022 if (!(cfg = ast_config_load(config_filename, config_flags))) {
13023 res = AST_TEST_FAIL;
13024 goto cleanup;
13025 }
13026
13027 load_config_from_memory(1, cfg, NULL);
13028 ast_config_destroy(cfg);
13029
13030 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13031 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13032 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13033
13034 AST_LIST_LOCK(&users);
13035 AST_LIST_TRAVERSE(&users, vmu, list) {
13036 if (!strcmp(vmu->mailbox, "00000001")) {
13037 if (0);
13038 CHECK(vmu, callback, "othercontext")
13039 CHECK(vmu, locale, "nl_NL.UTF-8")
13040 CHECK(vmu, zonetag, "central")
13041 } else if (!strcmp(vmu->mailbox, "00000002")) {
13042 if (0);
13043 CHECK(vmu, callback, "somecontext")
13044 CHECK(vmu, locale, "de_DE.UTF-8")
13045 CHECK(vmu, zonetag, "european")
13046 }
13047 }
13048 AST_LIST_UNLOCK(&users);
13049
13050 #undef CHECK
13051
13052
13053 load_config(1);
13054
13055 cleanup:
13056 unlink(config_filename);
13057 return res;
13058 }
13059
13060 #endif
13061
13062 static int reload(void)
13063 {
13064 return load_config(1);
13065 }
13066
13067 static int unload_module(void)
13068 {
13069 int res;
13070
13071 res = ast_unregister_application(app);
13072 res |= ast_unregister_application(app2);
13073 res |= ast_unregister_application(app3);
13074 res |= ast_unregister_application(app4);
13075 res |= ast_unregister_application(sayname_app);
13076 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13077 res |= ast_manager_unregister("VoicemailUsersList");
13078 res |= ast_data_unregister(NULL);
13079 #ifdef TEST_FRAMEWORK
13080 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13081 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13082 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13083 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13084 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13085 #endif
13086 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13087 ast_uninstall_vm_functions();
13088 ao2_ref(inprocess_container, -1);
13089
13090 if (poll_thread != AST_PTHREADT_NULL)
13091 stop_poll_thread();
13092
13093 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13094 ast_unload_realtime("voicemail");
13095 ast_unload_realtime("voicemail_data");
13096
13097 free_vm_users();
13098 free_vm_zones();
13099 return res;
13100 }
13101
13102 static int load_module(void)
13103 {
13104 int res;
13105 my_umask = umask(0);
13106 umask(my_umask);
13107
13108 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13109 return AST_MODULE_LOAD_DECLINE;
13110 }
13111
13112
13113 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13114
13115 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13116 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13117 }
13118
13119 if ((res = load_config(0)))
13120 return res;
13121
13122 res = ast_register_application_xml(app, vm_exec);
13123 res |= ast_register_application_xml(app2, vm_execmain);
13124 res |= ast_register_application_xml(app3, vm_box_exists);
13125 res |= ast_register_application_xml(app4, vmauthenticate);
13126 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13127 res |= ast_custom_function_register(&mailbox_exists_acf);
13128 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13129 #ifdef TEST_FRAMEWORK
13130 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13131 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13132 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13133 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13134 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13135 #endif
13136
13137 if (res)
13138 return res;
13139
13140 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13141 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13142
13143 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13144 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13145 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13146
13147 return res;
13148 }
13149
13150 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13151 {
13152 int cmd = 0;
13153 char destination[80] = "";
13154 int retries = 0;
13155
13156 if (!num) {
13157 ast_verb(3, "Destination number will be entered manually\n");
13158 while (retries < 3 && cmd != 't') {
13159 destination[1] = '\0';
13160 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13161 if (!cmd)
13162 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13163 if (!cmd)
13164 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13165 if (!cmd) {
13166 cmd = ast_waitfordigit(chan, 6000);
13167 if (cmd)
13168 destination[0] = cmd;
13169 }
13170 if (!cmd) {
13171 retries++;
13172 } else {
13173
13174 if (cmd < 0)
13175 return 0;
13176 if (cmd == '*') {
13177 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13178 return 0;
13179 }
13180 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13181 retries++;
13182 else
13183 cmd = 't';
13184 }
13185 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13186 }
13187 if (retries >= 3) {
13188 return 0;
13189 }
13190
13191 } else {
13192 if (option_verbose > 2)
13193 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13194 ast_copy_string(destination, num, sizeof(destination));
13195 }
13196
13197 if (!ast_strlen_zero(destination)) {
13198 if (destination[strlen(destination) -1 ] == '*')
13199 return 0;
13200 if (option_verbose > 2)
13201 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13202 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13203 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13204 chan->priority = 0;
13205 return 9;
13206 }
13207 return 0;
13208 }
13209
13210
13211
13212
13213
13214
13215
13216
13217
13218
13219
13220
13221
13222
13223 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)
13224 {
13225 int res = 0;
13226 char filename[PATH_MAX];
13227 struct ast_config *msg_cfg = NULL;
13228 const char *origtime, *context;
13229 char *name, *num;
13230 int retries = 0;
13231 char *cid;
13232 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13233
13234 vms->starting = 0;
13235
13236 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13237
13238
13239 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13240 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13241 msg_cfg = ast_config_load(filename, config_flags);
13242 DISPOSE(vms->curdir, vms->curmsg);
13243 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13244 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13245 return 0;
13246 }
13247
13248 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13249 ast_config_destroy(msg_cfg);
13250 return 0;
13251 }
13252
13253 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13254
13255 context = ast_variable_retrieve(msg_cfg, "message", "context");
13256 if (!strncasecmp("macro", context, 5))
13257 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13258 switch (option) {
13259 case 3:
13260 if (!res)
13261 res = play_message_datetime(chan, vmu, origtime, filename);
13262 if (!res)
13263 res = play_message_callerid(chan, vms, cid, context, 0);
13264
13265 res = 't';
13266 break;
13267
13268 case 2:
13269
13270 if (ast_strlen_zero(cid))
13271 break;
13272
13273 ast_callerid_parse(cid, &name, &num);
13274 while ((res > -1) && (res != 't')) {
13275 switch (res) {
13276 case '1':
13277 if (num) {
13278
13279 res = dialout(chan, vmu, num, vmu->callback);
13280 if (res) {
13281 ast_config_destroy(msg_cfg);
13282 return 9;
13283 }
13284 } else {
13285 res = '2';
13286 }
13287 break;
13288
13289 case '2':
13290
13291 if (!ast_strlen_zero(vmu->dialout)) {
13292 res = dialout(chan, vmu, NULL, vmu->dialout);
13293 if (res) {
13294 ast_config_destroy(msg_cfg);
13295 return 9;
13296 }
13297 } else {
13298 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13299 res = ast_play_and_wait(chan, "vm-sorry");
13300 }
13301 ast_config_destroy(msg_cfg);
13302 return res;
13303 case '*':
13304 res = 't';
13305 break;
13306 case '3':
13307 case '4':
13308 case '5':
13309 case '6':
13310 case '7':
13311 case '8':
13312 case '9':
13313 case '0':
13314
13315 res = ast_play_and_wait(chan, "vm-sorry");
13316 retries++;
13317 break;
13318 default:
13319 if (num) {
13320 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13321 res = ast_play_and_wait(chan, "vm-num-i-have");
13322 if (!res)
13323 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13324 if (!res)
13325 res = ast_play_and_wait(chan, "vm-tocallnum");
13326
13327 if (!ast_strlen_zero(vmu->dialout)) {
13328 if (!res)
13329 res = ast_play_and_wait(chan, "vm-calldiffnum");
13330 }
13331 } else {
13332 res = ast_play_and_wait(chan, "vm-nonumber");
13333 if (!ast_strlen_zero(vmu->dialout)) {
13334 if (!res)
13335 res = ast_play_and_wait(chan, "vm-toenternumber");
13336 }
13337 }
13338 if (!res) {
13339 res = ast_play_and_wait(chan, "vm-star-cancel");
13340 }
13341 if (!res) {
13342 res = ast_waitfordigit(chan, 6000);
13343 }
13344 if (!res) {
13345 retries++;
13346 if (retries > 3) {
13347 res = 't';
13348 }
13349 }
13350 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13351 break;
13352
13353 }
13354 if (res == 't')
13355 res = 0;
13356 else if (res == '*')
13357 res = -1;
13358 }
13359 break;
13360
13361 case 1:
13362
13363 if (ast_strlen_zero(cid))
13364 break;
13365
13366 ast_callerid_parse(cid, &name, &num);
13367 if (!num) {
13368 ast_verb(3, "No CID number available, no reply sent\n");
13369 if (!res)
13370 res = ast_play_and_wait(chan, "vm-nonumber");
13371 ast_config_destroy(msg_cfg);
13372 return res;
13373 } else {
13374 struct ast_vm_user vmu2;
13375 if (find_user(&vmu2, vmu->context, num)) {
13376 struct leave_vm_options leave_options;
13377 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13378 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13379
13380 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13381
13382 memset(&leave_options, 0, sizeof(leave_options));
13383 leave_options.record_gain = record_gain;
13384 res = leave_voicemail(chan, mailbox, &leave_options);
13385 if (!res)
13386 res = 't';
13387 ast_config_destroy(msg_cfg);
13388 return res;
13389 } else {
13390
13391 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13392 ast_play_and_wait(chan, "vm-nobox");
13393 res = 't';
13394 ast_config_destroy(msg_cfg);
13395 return res;
13396 }
13397 }
13398 res = 0;
13399
13400 break;
13401 }
13402
13403 #ifndef IMAP_STORAGE
13404 ast_config_destroy(msg_cfg);
13405
13406 if (!res) {
13407 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13408 vms->heard[msg] = 1;
13409 res = wait_file(chan, vms, vms->fn);
13410 }
13411 #endif
13412 return res;
13413 }
13414
13415 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13416 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13417 signed char record_gain, struct vm_state *vms, char *flag)
13418 {
13419
13420 int res = 0;
13421 int cmd = 0;
13422 int max_attempts = 3;
13423 int attempts = 0;
13424 int recorded = 0;
13425 int msg_exists = 0;
13426 signed char zero_gain = 0;
13427 char tempfile[PATH_MAX];
13428 char *acceptdtmf = "#";
13429 char *canceldtmf = "";
13430 int canceleddtmf = 0;
13431
13432
13433
13434
13435 if (duration == NULL) {
13436 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13437 return -1;
13438 }
13439
13440 if (!outsidecaller)
13441 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13442 else
13443 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13444
13445 cmd = '3';
13446
13447 while ((cmd >= 0) && (cmd != 't')) {
13448 switch (cmd) {
13449 case '1':
13450 if (!msg_exists) {
13451
13452 cmd = '3';
13453 break;
13454 } else {
13455
13456 ast_verb(3, "Saving message as is\n");
13457 if (!outsidecaller)
13458 ast_filerename(tempfile, recordfile, NULL);
13459 ast_stream_and_wait(chan, "vm-msgsaved", "");
13460 if (!outsidecaller) {
13461
13462 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13463 DISPOSE(recordfile, -1);
13464 }
13465 cmd = 't';
13466 return res;
13467 }
13468 case '2':
13469
13470 ast_verb(3, "Reviewing the message\n");
13471 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13472 break;
13473 case '3':
13474 msg_exists = 0;
13475
13476 if (recorded == 1)
13477 ast_verb(3, "Re-recording the message\n");
13478 else
13479 ast_verb(3, "Recording the message\n");
13480
13481 if (recorded && outsidecaller) {
13482 cmd = ast_play_and_wait(chan, INTRO);
13483 cmd = ast_play_and_wait(chan, "beep");
13484 }
13485 recorded = 1;
13486
13487 if (record_gain)
13488 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13489 if (ast_test_flag(vmu, VM_OPERATOR))
13490 canceldtmf = "0";
13491 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13492 if (strchr(canceldtmf, cmd)) {
13493
13494 canceleddtmf = 1;
13495 }
13496 if (record_gain)
13497 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13498 if (cmd == -1) {
13499
13500 if (!outsidecaller) {
13501
13502 ast_filedelete(tempfile, NULL);
13503 }
13504 return cmd;
13505 }
13506 if (cmd == '0') {
13507 break;
13508 } else if (cmd == '*') {
13509 break;
13510 #if 0
13511 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13512
13513 ast_verb(3, "Message too short\n");
13514 cmd = ast_play_and_wait(chan, "vm-tooshort");
13515 cmd = ast_filedelete(tempfile, NULL);
13516 break;
13517 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13518
13519 ast_verb(3, "Nothing recorded\n");
13520 cmd = ast_filedelete(tempfile, NULL);
13521 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13522 if (!cmd)
13523 cmd = ast_play_and_wait(chan, "vm-speakup");
13524 break;
13525 #endif
13526 } else {
13527
13528 msg_exists = 1;
13529 cmd = 0;
13530 }
13531 break;
13532 case '4':
13533 if (outsidecaller) {
13534
13535 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13536 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13537 res = ast_play_and_wait(chan, "vm-marked-urgent");
13538 strcpy(flag, "Urgent");
13539 } else if (flag) {
13540 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13541 res = ast_play_and_wait(chan, "vm-urgent-removed");
13542 strcpy(flag, "");
13543 } else {
13544 ast_play_and_wait(chan, "vm-sorry");
13545 }
13546 cmd = 0;
13547 } else {
13548 cmd = ast_play_and_wait(chan, "vm-sorry");
13549 }
13550 break;
13551 case '5':
13552 case '6':
13553 case '7':
13554 case '8':
13555 case '9':
13556 case '*':
13557 case '#':
13558 cmd = ast_play_and_wait(chan, "vm-sorry");
13559 break;
13560 #if 0
13561
13562
13563 case '*':
13564
13565 cmd = ast_play_and_wait(chan, "vm-deleted");
13566 cmd = ast_filedelete(tempfile, NULL);
13567 if (outsidecaller) {
13568 res = vm_exec(chan, NULL);
13569 return res;
13570 }
13571 else
13572 return 1;
13573 #endif
13574 case '0':
13575 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13576 cmd = ast_play_and_wait(chan, "vm-sorry");
13577 break;
13578 }
13579 if (msg_exists || recorded) {
13580 cmd = ast_play_and_wait(chan, "vm-saveoper");
13581 if (!cmd)
13582 cmd = ast_waitfordigit(chan, 3000);
13583 if (cmd == '1') {
13584 ast_filerename(tempfile, recordfile, NULL);
13585 ast_play_and_wait(chan, "vm-msgsaved");
13586 cmd = '0';
13587 } else if (cmd == '4') {
13588 if (flag) {
13589 ast_play_and_wait(chan, "vm-marked-urgent");
13590 strcpy(flag, "Urgent");
13591 }
13592 ast_play_and_wait(chan, "vm-msgsaved");
13593 cmd = '0';
13594 } else {
13595 ast_play_and_wait(chan, "vm-deleted");
13596 DELETE(tempfile, -1, tempfile, vmu);
13597 cmd = '0';
13598 }
13599 }
13600 return cmd;
13601 default:
13602
13603
13604
13605 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13606 return cmd;
13607 if (msg_exists) {
13608 cmd = ast_play_and_wait(chan, "vm-review");
13609 if (!cmd && outsidecaller) {
13610 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13611 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13612 } else if (flag) {
13613 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13614 }
13615 }
13616 } else {
13617 cmd = ast_play_and_wait(chan, "vm-torerecord");
13618 if (!cmd)
13619 cmd = ast_waitfordigit(chan, 600);
13620 }
13621
13622 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13623 cmd = ast_play_and_wait(chan, "vm-reachoper");
13624 if (!cmd)
13625 cmd = ast_waitfordigit(chan, 600);
13626 }
13627 #if 0
13628 if (!cmd)
13629 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13630 #endif
13631 if (!cmd)
13632 cmd = ast_waitfordigit(chan, 6000);
13633 if (!cmd) {
13634 attempts++;
13635 }
13636 if (attempts > max_attempts) {
13637 cmd = 't';
13638 }
13639 }
13640 }
13641 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13642
13643 ast_filedelete(tempfile, NULL);
13644 }
13645
13646 if (cmd != 't' && outsidecaller)
13647 ast_play_and_wait(chan, "vm-goodbye");
13648
13649 return cmd;
13650 }
13651
13652
13653
13654
13655
13656 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13657 .load = load_module,
13658 .unload = unload_module,
13659 .reload = reload,
13660 .nonoptreq = "res_adsi,res_smdi",
13661 );