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: 426691 $")
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 language[MAX_LANGUAGE];
00625 char zonetag[80];
00626 char locale[20];
00627 char callback[80];
00628 char dialout[80];
00629 char uniqueid[80];
00630 char exit[80];
00631 char attachfmt[20];
00632 unsigned int flags;
00633 int saydurationm;
00634 int minsecs;
00635 int maxmsg;
00636 int maxdeletedmsg;
00637 int maxsecs;
00638 int passwordlocation;
00639 #ifdef IMAP_STORAGE
00640 char imapuser[80];
00641 char imappassword[80];
00642 char imapfolder[64];
00643 char imapvmshareid[80];
00644 int imapversion;
00645 #endif
00646 double volgain;
00647 AST_LIST_ENTRY(ast_vm_user) list;
00648 };
00649
00650
00651 struct vm_zone {
00652 AST_LIST_ENTRY(vm_zone) list;
00653 char name[80];
00654 char timezone[80];
00655 char msg_format[512];
00656 };
00657
00658 #define VMSTATE_MAX_MSG_ARRAY 256
00659
00660
00661 struct vm_state {
00662 char curbox[80];
00663 char username[80];
00664 char context[80];
00665 char curdir[PATH_MAX];
00666 char vmbox[PATH_MAX];
00667 char fn[PATH_MAX];
00668 char intro[PATH_MAX];
00669 int *deleted;
00670 int *heard;
00671 int dh_arraysize;
00672 int curmsg;
00673 int lastmsg;
00674 int newmessages;
00675 int oldmessages;
00676 int urgentmessages;
00677 int starting;
00678 int repeats;
00679 #ifdef IMAP_STORAGE
00680 ast_mutex_t lock;
00681 int updated;
00682 long *msgArray;
00683 unsigned msg_array_max;
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 = ast_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 memset(retval, 0, sizeof(*retval));
01385 }
01386 populate_defaults(retval);
01387 if (!ivm) {
01388 ast_set_flag(retval, VM_ALLOCED);
01389 }
01390 if (mailbox) {
01391 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01392 }
01393 if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
01394 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01395 } else {
01396 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01397 }
01398 if (var) {
01399 apply_options_full(retval, var);
01400 ast_variables_destroy(var);
01401 } else {
01402 if (!ivm)
01403 free_user(retval);
01404 retval = NULL;
01405 }
01406 }
01407 return retval;
01408 }
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01419 {
01420
01421 struct ast_vm_user *vmu = NULL, *cur;
01422 AST_LIST_LOCK(&users);
01423
01424 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01425 context = "default";
01426
01427 AST_LIST_TRAVERSE(&users, cur, list) {
01428 #ifdef IMAP_STORAGE
01429 if (cur->imapversion != imapversion) {
01430 continue;
01431 }
01432 #endif
01433 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01434 break;
01435 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01436 break;
01437 }
01438 if (cur) {
01439
01440 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01441 *vmu = *cur;
01442 if (!ivm) {
01443 vmu->emailbody = ast_strdup(cur->emailbody);
01444 vmu->emailsubject = ast_strdup(cur->emailsubject);
01445 }
01446 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01447 AST_LIST_NEXT(vmu, list) = NULL;
01448 }
01449 } else
01450 vmu = find_user_realtime(ivm, context, mailbox);
01451 AST_LIST_UNLOCK(&users);
01452 return vmu;
01453 }
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01466 {
01467
01468 struct ast_vm_user *cur;
01469 int res = -1;
01470 AST_LIST_LOCK(&users);
01471 AST_LIST_TRAVERSE(&users, cur, list) {
01472 if ((!context || !strcasecmp(context, cur->context)) &&
01473 (!strcasecmp(mailbox, cur->mailbox)))
01474 break;
01475 }
01476 if (cur) {
01477 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01478 res = 0;
01479 }
01480 AST_LIST_UNLOCK(&users);
01481 return res;
01482 }
01483
01484
01485
01486
01487 static inline int valid_config(const struct ast_config *cfg)
01488 {
01489 return cfg && cfg != CONFIG_STATUS_FILEINVALID;
01490 }
01491
01492
01493
01494
01495
01496
01497
01498
01499 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01500 {
01501 struct ast_config *cfg = NULL;
01502 struct ast_variable *var = NULL;
01503 struct ast_category *cat = NULL;
01504 char *category = NULL, *value = NULL, *new = NULL;
01505 const char *tmp = NULL;
01506 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01507 char secretfn[PATH_MAX] = "";
01508 int found = 0;
01509
01510 if (!change_password_realtime(vmu, newpassword))
01511 return;
01512
01513
01514 switch (vmu->passwordlocation) {
01515 case OPT_PWLOC_SPOOLDIR:
01516 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01517 if (write_password_to_file(secretfn, newpassword) == 0) {
01518 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01519 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01520 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01521 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01522 break;
01523 } else {
01524 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01525 }
01526
01527 case OPT_PWLOC_VOICEMAILCONF:
01528 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
01529 while ((category = ast_category_browse(cfg, category))) {
01530 if (!strcasecmp(category, vmu->context)) {
01531 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01532 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01533 break;
01534 }
01535 value = strstr(tmp, ",");
01536 if (!value) {
01537 new = ast_alloca(strlen(newpassword)+1);
01538 sprintf(new, "%s", newpassword);
01539 } else {
01540 new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
01541 sprintf(new, "%s%s", newpassword, value);
01542 }
01543 if (!(cat = ast_category_get(cfg, category))) {
01544 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01545 break;
01546 }
01547 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01548 found = 1;
01549 }
01550 }
01551
01552 if (found) {
01553 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01554 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01555 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01556 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01557 ast_config_destroy(cfg);
01558 break;
01559 }
01560
01561 ast_config_destroy(cfg);
01562 }
01563
01564 case OPT_PWLOC_USERSCONF:
01565
01566
01567 if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
01568 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01569 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01570 ast_debug(4, "users.conf: %s\n", category);
01571 if (!strcasecmp(category, vmu->mailbox)) {
01572 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01573 ast_debug(3, "looks like we need to make vmsecret!\n");
01574 var = ast_variable_new("vmsecret", newpassword, "");
01575 } else {
01576 var = NULL;
01577 }
01578 new = ast_alloca(strlen(newpassword) + 1);
01579 sprintf(new, "%s", newpassword);
01580 if (!(cat = ast_category_get(cfg, category))) {
01581 ast_debug(4, "failed to get category!\n");
01582 ast_free(var);
01583 break;
01584 }
01585 if (!var) {
01586 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01587 } else {
01588 ast_variable_append(cat, var);
01589 }
01590 found = 1;
01591 break;
01592 }
01593 }
01594
01595 if (found) {
01596 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01597 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01598 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01599 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01600 }
01601
01602 ast_config_destroy(cfg);
01603 }
01604 }
01605 }
01606
01607 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01608 {
01609 char buf[255];
01610 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01611 ast_debug(1, "External password: %s\n",buf);
01612 if (!ast_safe_system(buf)) {
01613 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01614 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01615
01616 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01617 }
01618 }
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01634 {
01635 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01636 }
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650 static int make_file(char *dest, const int len, const char *dir, const int num)
01651 {
01652 return snprintf(dest, len, "%s/msg%04d", dir, num);
01653 }
01654
01655
01656 static FILE *vm_mkftemp(char *template)
01657 {
01658 FILE *p = NULL;
01659 int pfd = mkstemp(template);
01660 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01661 if (pfd > -1) {
01662 p = fdopen(pfd, "w+");
01663 if (!p) {
01664 close(pfd);
01665 pfd = -1;
01666 }
01667 }
01668 return p;
01669 }
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01680 {
01681 mode_t mode = VOICEMAIL_DIR_MODE;
01682 int res;
01683
01684 make_dir(dest, len, context, ext, folder);
01685 if ((res = ast_mkdir(dest, mode))) {
01686 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01687 return -1;
01688 }
01689 return 0;
01690 }
01691
01692 static const char * const mailbox_folders[] = {
01693 #ifdef IMAP_STORAGE
01694 imapfolder,
01695 #else
01696 "INBOX",
01697 #endif
01698 "Old",
01699 "Work",
01700 "Family",
01701 "Friends",
01702 "Cust1",
01703 "Cust2",
01704 "Cust3",
01705 "Cust4",
01706 "Cust5",
01707 "Deleted",
01708 "Urgent",
01709 };
01710
01711 static const char *mbox(struct ast_vm_user *vmu, int id)
01712 {
01713 #ifdef IMAP_STORAGE
01714 if (vmu && id == 0) {
01715 return vmu->imapfolder;
01716 }
01717 #endif
01718 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01719 }
01720
01721 static int get_folder_by_name(const char *name)
01722 {
01723 size_t i;
01724
01725 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01726 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01727 return i;
01728 }
01729 }
01730
01731 return -1;
01732 }
01733
01734 static void free_user(struct ast_vm_user *vmu)
01735 {
01736 if (ast_test_flag(vmu, VM_ALLOCED)) {
01737
01738 ast_free(vmu->emailbody);
01739 vmu->emailbody = NULL;
01740
01741 ast_free(vmu->emailsubject);
01742 vmu->emailsubject = NULL;
01743
01744 ast_free(vmu);
01745 }
01746 }
01747
01748 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01749
01750 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01751
01752
01753 if (vms->deleted) {
01754 ast_free(vms->deleted);
01755 vms->deleted = NULL;
01756 }
01757 if (vms->heard) {
01758 ast_free(vms->heard);
01759 vms->heard = NULL;
01760 }
01761 vms->dh_arraysize = 0;
01762
01763 if (arraysize > 0) {
01764 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01765 return -1;
01766 }
01767 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01768 ast_free(vms->deleted);
01769 vms->deleted = NULL;
01770 return -1;
01771 }
01772 vms->dh_arraysize = arraysize;
01773 }
01774
01775 return 0;
01776 }
01777
01778
01779
01780 #ifdef IMAP_STORAGE
01781 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01782 {
01783 char arg[10];
01784 struct vm_state *vms;
01785 unsigned long messageNum;
01786
01787
01788 if (msgnum < 0 && !imapgreetings) {
01789 ast_filedelete(file, NULL);
01790 return;
01791 }
01792
01793 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01794 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);
01795 return;
01796 }
01797
01798 if (msgnum < 0) {
01799 imap_delete_old_greeting(file, vms);
01800 return;
01801 }
01802
01803
01804
01805 messageNum = vms->msgArray[msgnum];
01806 if (messageNum == 0) {
01807 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01808 return;
01809 }
01810 if (option_debug > 2)
01811 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01812
01813 snprintf (arg, sizeof(arg), "%lu", messageNum);
01814 ast_mutex_lock(&vms->lock);
01815 mail_setflag (vms->mailstream, arg, "\\DELETED");
01816 mail_expunge(vms->mailstream);
01817 ast_mutex_unlock(&vms->lock);
01818 }
01819
01820 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01821 {
01822 struct vm_state *vms_p;
01823 char *file, *filename;
01824 char *attachment;
01825 int i;
01826 BODY *body;
01827
01828
01829
01830
01831 if (msgnum > -1 || !imapgreetings) {
01832 return 0;
01833 } else {
01834 file = strrchr(ast_strdupa(dir), '/');
01835 if (file)
01836 *file++ = '\0';
01837 else {
01838 ast_debug (1, "Failed to procure file name from directory passed.\n");
01839 return -1;
01840 }
01841 }
01842
01843
01844 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01845 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01846
01847
01848
01849
01850 if (!(vms_p = create_vm_state_from_user(vmu))) {
01851 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01852 return -1;
01853 }
01854 }
01855
01856
01857 *vms_p->introfn = '\0';
01858
01859 ast_mutex_lock(&vms_p->lock);
01860 init_mailstream(vms_p, GREETINGS_FOLDER);
01861 if (!vms_p->mailstream) {
01862 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01863 ast_mutex_unlock(&vms_p->lock);
01864 return -1;
01865 }
01866
01867
01868 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01869 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01870
01871 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01872 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01873 } else {
01874 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01875 ast_mutex_unlock(&vms_p->lock);
01876 return -1;
01877 }
01878 filename = strsep(&attachment, ".");
01879 if (!strcmp(filename, file)) {
01880 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01881 vms_p->msgArray[vms_p->curmsg] = i + 1;
01882 save_body(body, vms_p, "2", attachment, 0);
01883 ast_mutex_unlock(&vms_p->lock);
01884 return 0;
01885 }
01886 }
01887 ast_mutex_unlock(&vms_p->lock);
01888
01889 return -1;
01890 }
01891
01892 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01893 {
01894 BODY *body;
01895 char *header_content;
01896 char *attachedfilefmt;
01897 char buf[80];
01898 struct vm_state *vms;
01899 char text_file[PATH_MAX];
01900 FILE *text_file_ptr;
01901 int res = 0;
01902 struct ast_vm_user *vmu;
01903
01904 if (!(vmu = find_user(NULL, context, mailbox))) {
01905 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01906 return -1;
01907 }
01908
01909 if (msgnum < 0) {
01910 if (imapgreetings) {
01911 res = imap_retrieve_greeting(dir, msgnum, vmu);
01912 goto exit;
01913 } else {
01914 res = 0;
01915 goto exit;
01916 }
01917 }
01918
01919
01920
01921
01922 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01923
01924
01925
01926
01927
01928
01929
01930 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01931 res = -1;
01932 goto exit;
01933 }
01934
01935 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01936 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01937
01938
01939 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01940 res = 0;
01941 goto exit;
01942 }
01943
01944 if (option_debug > 2)
01945 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01946 if (vms->msgArray[msgnum] == 0) {
01947 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01948 res = -1;
01949 goto exit;
01950 }
01951
01952
01953 ast_mutex_lock(&vms->lock);
01954 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01955 ast_mutex_unlock(&vms->lock);
01956
01957 if (ast_strlen_zero(header_content)) {
01958 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01959 res = -1;
01960 goto exit;
01961 }
01962
01963 ast_mutex_lock(&vms->lock);
01964 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01965 ast_mutex_unlock(&vms->lock);
01966
01967
01968 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01969 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01970 } else {
01971 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01972 res = -1;
01973 goto exit;
01974 }
01975
01976
01977
01978 strsep(&attachedfilefmt, ".");
01979 if (!attachedfilefmt) {
01980 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01981 res = -1;
01982 goto exit;
01983 }
01984
01985 save_body(body, vms, "2", attachedfilefmt, 0);
01986 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01987 *vms->introfn = '\0';
01988 }
01989
01990
01991 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01992
01993 if (!(text_file_ptr = fopen(text_file, "w"))) {
01994 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01995 }
01996
01997 fprintf(text_file_ptr, "%s\n", "[message]");
01998
01999 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02000 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02001 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02002 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02003 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02004 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02005 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02006 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02007 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02008 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02009 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02010 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02011 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02012 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02013 fclose(text_file_ptr);
02014
02015 exit:
02016 free_user(vmu);
02017 return res;
02018 }
02019
02020 static int folder_int(const char *folder)
02021 {
02022
02023 if (!folder) {
02024 return 0;
02025 }
02026 if (!strcasecmp(folder, imapfolder)) {
02027 return 0;
02028 } else if (!strcasecmp(folder, "Old")) {
02029 return 1;
02030 } else if (!strcasecmp(folder, "Work")) {
02031 return 2;
02032 } else if (!strcasecmp(folder, "Family")) {
02033 return 3;
02034 } else if (!strcasecmp(folder, "Friends")) {
02035 return 4;
02036 } else if (!strcasecmp(folder, "Cust1")) {
02037 return 5;
02038 } else if (!strcasecmp(folder, "Cust2")) {
02039 return 6;
02040 } else if (!strcasecmp(folder, "Cust3")) {
02041 return 7;
02042 } else if (!strcasecmp(folder, "Cust4")) {
02043 return 8;
02044 } else if (!strcasecmp(folder, "Cust5")) {
02045 return 9;
02046 } else if (!strcasecmp(folder, "Urgent")) {
02047 return 11;
02048 } else {
02049 return 0;
02050 }
02051 }
02052
02053 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02054 {
02055 SEARCHPGM *pgm;
02056 SEARCHHEADER *hdr;
02057
02058 struct ast_vm_user *vmu, vmus;
02059 struct vm_state *vms_p;
02060 int ret = 0;
02061 int fold = folder_int(folder);
02062 int urgent = 0;
02063
02064
02065 if (fold == 11) {
02066 fold = NEW_FOLDER;
02067 urgent = 1;
02068 }
02069
02070 if (ast_strlen_zero(mailbox))
02071 return 0;
02072
02073
02074 vmu = find_user(&vmus, context, mailbox);
02075 if (!vmu) {
02076 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02077 return -1;
02078 } else {
02079
02080 if (vmu->imapuser[0] == '\0') {
02081 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02082 return -1;
02083 }
02084 }
02085
02086
02087 if (vmu->imapuser[0] == '\0') {
02088 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02089 free_user(vmu);
02090 return -1;
02091 }
02092 ast_assert(msgnum < vms->msg_array_max);
02093
02094
02095 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02096 if (!vms_p) {
02097 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02098 }
02099 if (vms_p) {
02100 ast_debug(3, "Returning before search - user is logged in\n");
02101 if (fold == 0) {
02102 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02103 }
02104 if (fold == 1) {
02105 return vms_p->oldmessages;
02106 }
02107 }
02108
02109
02110 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02111 if (!vms_p) {
02112 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02113 }
02114
02115 if (!vms_p) {
02116 vms_p = create_vm_state_from_user(vmu);
02117 }
02118 ret = init_mailstream(vms_p, fold);
02119 if (!vms_p->mailstream) {
02120 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02121 return -1;
02122 }
02123 if (ret == 0) {
02124 ast_mutex_lock(&vms_p->lock);
02125 pgm = mail_newsearchpgm ();
02126 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02127 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02128 pgm->header = hdr;
02129 if (fold != OLD_FOLDER) {
02130 pgm->unseen = 1;
02131 pgm->seen = 0;
02132 }
02133
02134
02135
02136 else {
02137 pgm->unseen = 0;
02138 pgm->seen = 1;
02139 }
02140
02141 if (fold == NEW_FOLDER) {
02142 if (urgent) {
02143 pgm->flagged = 1;
02144 pgm->unflagged = 0;
02145 } else {
02146 pgm->flagged = 0;
02147 pgm->unflagged = 1;
02148 }
02149 }
02150 pgm->undeleted = 1;
02151 pgm->deleted = 0;
02152
02153 vms_p->vmArrayIndex = 0;
02154 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02155 if (fold == 0 && urgent == 0)
02156 vms_p->newmessages = vms_p->vmArrayIndex;
02157 if (fold == 1)
02158 vms_p->oldmessages = vms_p->vmArrayIndex;
02159 if (fold == 0 && urgent == 1)
02160 vms_p->urgentmessages = vms_p->vmArrayIndex;
02161
02162 mail_free_searchpgm(&pgm);
02163 ast_mutex_unlock(&vms_p->lock);
02164 vms_p->updated = 0;
02165 return vms_p->vmArrayIndex;
02166 } else {
02167 ast_mutex_lock(&vms_p->lock);
02168 mail_ping(vms_p->mailstream);
02169 ast_mutex_unlock(&vms_p->lock);
02170 }
02171 return 0;
02172 }
02173
02174 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02175 {
02176
02177 check_quota(vms, vmu->imapfolder);
02178 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02179 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02180 ast_play_and_wait(chan, "vm-mailboxfull");
02181 return -1;
02182 }
02183
02184
02185 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));
02186 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02187 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02188 ast_play_and_wait(chan, "vm-mailboxfull");
02189 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02190 return -1;
02191 }
02192
02193 return 0;
02194 }
02195
02196
02197
02198
02199
02200
02201
02202
02203
02204
02205 static int messagecount(const char *context, const char *mailbox, const char *folder)
02206 {
02207 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02208 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02209 } else {
02210 return __messagecount(context, mailbox, folder);
02211 }
02212 }
02213
02214 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)
02215 {
02216 char *myserveremail = serveremail;
02217 char fn[PATH_MAX];
02218 char introfn[PATH_MAX];
02219 char mailbox[256];
02220 char *stringp;
02221 FILE *p = NULL;
02222 char tmp[80] = "/tmp/astmail-XXXXXX";
02223 long len;
02224 void *buf;
02225 int tempcopy = 0;
02226 STRING str;
02227 int ret;
02228 char *imap_flags = NIL;
02229 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02230 int box = NEW_FOLDER;
02231
02232
02233 if (msgnum < 0) {
02234 if(!imapgreetings) {
02235 return 0;
02236 } else {
02237 box = GREETINGS_FOLDER;
02238 }
02239 }
02240
02241 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02242 return -1;
02243 }
02244
02245
02246 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02247 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02248 imap_flags = "\\FLAGGED";
02249 }
02250
02251
02252 fmt = ast_strdupa(fmt);
02253 stringp = fmt;
02254 strsep(&stringp, "|");
02255
02256 if (!ast_strlen_zero(vmu->serveremail))
02257 myserveremail = vmu->serveremail;
02258
02259 if (msgnum > -1)
02260 make_file(fn, sizeof(fn), dir, msgnum);
02261 else
02262 ast_copy_string (fn, dir, sizeof(fn));
02263
02264 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02265 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02266 *introfn = '\0';
02267 }
02268
02269 if (ast_strlen_zero(vmu->email)) {
02270
02271
02272
02273
02274
02275 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02276 tempcopy = 1;
02277 }
02278
02279 if (!strcmp(fmt, "wav49"))
02280 fmt = "WAV";
02281 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02282
02283
02284
02285 if (!(p = vm_mkftemp(tmp))) {
02286 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02287 if (tempcopy)
02288 *(vmu->email) = '\0';
02289 return -1;
02290 }
02291
02292 if (msgnum < 0 && imapgreetings) {
02293 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02294 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02295 return -1;
02296 }
02297 imap_delete_old_greeting(fn, vms);
02298 }
02299
02300 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02301 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02302 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02303 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02304
02305 len = ftell(p);
02306 rewind(p);
02307 if (!(buf = ast_malloc(len + 1))) {
02308 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02309 fclose(p);
02310 if (tempcopy)
02311 *(vmu->email) = '\0';
02312 return -1;
02313 }
02314 if (fread(buf, len, 1, p) < len) {
02315 if (ferror(p)) {
02316 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02317 return -1;
02318 }
02319 }
02320 ((char *) buf)[len] = '\0';
02321 INIT(&str, mail_string, buf, len);
02322 ret = init_mailstream(vms, box);
02323 if (ret == 0) {
02324 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02325 ast_mutex_lock(&vms->lock);
02326 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02327 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02328 ast_mutex_unlock(&vms->lock);
02329 fclose(p);
02330 unlink(tmp);
02331 ast_free(buf);
02332 } else {
02333 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02334 fclose(p);
02335 unlink(tmp);
02336 ast_free(buf);
02337 return -1;
02338 }
02339 ast_debug(3, "%s stored\n", fn);
02340
02341 if (tempcopy)
02342 *(vmu->email) = '\0';
02343 inprocess_count(vmu->mailbox, vmu->context, -1);
02344 return 0;
02345
02346 }
02347
02348
02349
02350
02351
02352
02353
02354
02355
02356
02357
02358
02359
02360
02361 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02362 {
02363 char tmp[PATH_MAX] = "";
02364 char *mailboxnc;
02365 char *context;
02366 char *mb;
02367 char *cur;
02368 if (newmsgs)
02369 *newmsgs = 0;
02370 if (oldmsgs)
02371 *oldmsgs = 0;
02372 if (urgentmsgs)
02373 *urgentmsgs = 0;
02374
02375 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02376
02377 if (ast_strlen_zero(mailbox_context))
02378 return 0;
02379
02380 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02381 context = strchr(tmp, '@');
02382 if (strchr(mailbox_context, ',')) {
02383 int tmpnew, tmpold, tmpurgent;
02384 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02385 mb = tmp;
02386 while ((cur = strsep(&mb, ", "))) {
02387 if (!ast_strlen_zero(cur)) {
02388 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02389 return -1;
02390 else {
02391 if (newmsgs)
02392 *newmsgs += tmpnew;
02393 if (oldmsgs)
02394 *oldmsgs += tmpold;
02395 if (urgentmsgs)
02396 *urgentmsgs += tmpurgent;
02397 }
02398 }
02399 }
02400 return 0;
02401 }
02402 if (context) {
02403 *context = '\0';
02404 mailboxnc = tmp;
02405 context++;
02406 } else {
02407 context = "default";
02408 mailboxnc = (char *) mailbox_context;
02409 }
02410
02411 if (newmsgs) {
02412 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02413 if (!vmu) {
02414 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02415 return -1;
02416 }
02417 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02418 free_user(vmu);
02419 return -1;
02420 }
02421 free_user(vmu);
02422 }
02423 if (oldmsgs) {
02424 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02425 return -1;
02426 }
02427 }
02428 if (urgentmsgs) {
02429 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02430 return -1;
02431 }
02432 }
02433 return 0;
02434 }
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446 static int has_voicemail(const char *mailbox, const char *folder)
02447 {
02448 char tmp[256], *tmp2, *box, *context;
02449 ast_copy_string(tmp, mailbox, sizeof(tmp));
02450 tmp2 = tmp;
02451 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02452 while ((box = strsep(&tmp2, ",&"))) {
02453 if (!ast_strlen_zero(box)) {
02454 if (has_voicemail(box, folder)) {
02455 return 1;
02456 }
02457 }
02458 }
02459 }
02460 if ((context = strchr(tmp, '@'))) {
02461 *context++ = '\0';
02462 } else {
02463 context = "default";
02464 }
02465 return __messagecount(context, tmp, folder) ? 1 : 0;
02466 }
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483 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)
02484 {
02485 struct vm_state *sendvms = NULL, *destvms = NULL;
02486 char messagestring[10];
02487 if (msgnum >= recip->maxmsg) {
02488 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02489 return -1;
02490 }
02491 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02492 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02493 return -1;
02494 }
02495 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02496 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02497 return -1;
02498 }
02499 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02500 ast_mutex_lock(&sendvms->lock);
02501 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02502 ast_mutex_unlock(&sendvms->lock);
02503 return 0;
02504 }
02505 ast_mutex_unlock(&sendvms->lock);
02506 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02507 return -1;
02508 }
02509
02510 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02511 {
02512 char tmp[256], *t = tmp;
02513 size_t left = sizeof(tmp);
02514
02515 if (box == OLD_FOLDER) {
02516 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02517 } else {
02518 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02519 }
02520
02521 if (box == NEW_FOLDER) {
02522 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02523 } else {
02524 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02525 }
02526
02527
02528 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02529
02530
02531 if (!ast_strlen_zero(authuser))
02532 ast_build_string(&t, &left, "/authuser=%s", authuser);
02533
02534
02535 if (!ast_strlen_zero(imapflags))
02536 ast_build_string(&t, &left, "/%s", imapflags);
02537
02538
02539 #if 1
02540 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02541 #else
02542 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02543 #endif
02544 if (box == NEW_FOLDER || box == OLD_FOLDER)
02545 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02546 else if (box == GREETINGS_FOLDER)
02547 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02548 else {
02549 if (!ast_strlen_zero(imapparentfolder)) {
02550
02551 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02552 } else {
02553 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02554 }
02555 }
02556 }
02557
02558 static int init_mailstream(struct vm_state *vms, int box)
02559 {
02560 MAILSTREAM *stream = NIL;
02561 long debug;
02562 char tmp[256];
02563
02564 if (!vms) {
02565 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02566 return -1;
02567 }
02568 if (option_debug > 2)
02569 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02570 if (vms->mailstream == NIL || !vms->mailstream) {
02571 if (option_debug)
02572 ast_log(LOG_DEBUG, "mailstream not set.\n");
02573 } else {
02574 stream = vms->mailstream;
02575 }
02576
02577 debug = NIL;
02578
02579 if (delimiter == '\0') {
02580 char *cp;
02581 #ifdef USE_SYSTEM_IMAP
02582 #include <imap/linkage.c>
02583 #elif defined(USE_SYSTEM_CCLIENT)
02584 #include <c-client/linkage.c>
02585 #else
02586 #include "linkage.c"
02587 #endif
02588
02589 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02590 ast_mutex_lock(&vms->lock);
02591 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02592 ast_mutex_unlock(&vms->lock);
02593 if (stream == NIL) {
02594 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02595 return -1;
02596 }
02597 get_mailbox_delimiter(stream);
02598
02599 for (cp = vms->imapfolder; *cp; cp++)
02600 if (*cp == '/')
02601 *cp = delimiter;
02602 }
02603
02604 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02605 if (option_debug > 2)
02606 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02607 ast_mutex_lock(&vms->lock);
02608 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02609 ast_mutex_unlock(&vms->lock);
02610 if (vms->mailstream == NIL) {
02611 return -1;
02612 } else {
02613 return 0;
02614 }
02615 }
02616
02617 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02618 {
02619 SEARCHPGM *pgm;
02620 SEARCHHEADER *hdr;
02621 int ret, urgent = 0;
02622
02623
02624 if (box == 11) {
02625 box = NEW_FOLDER;
02626 urgent = 1;
02627 }
02628
02629 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02630 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02631 vms->imapversion = vmu->imapversion;
02632 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02633
02634 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02635 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02636 return -1;
02637 }
02638
02639 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02640
02641
02642 if (box == 0) {
02643 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02644 check_quota(vms, (char *) mbox(vmu, box));
02645 }
02646
02647 ast_mutex_lock(&vms->lock);
02648 pgm = mail_newsearchpgm();
02649
02650
02651 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02652 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02653 pgm->header = hdr;
02654 pgm->deleted = 0;
02655 pgm->undeleted = 1;
02656
02657
02658 if (box == NEW_FOLDER && urgent == 1) {
02659 pgm->unseen = 1;
02660 pgm->seen = 0;
02661 pgm->flagged = 1;
02662 pgm->unflagged = 0;
02663 } else if (box == NEW_FOLDER && urgent == 0) {
02664 pgm->unseen = 1;
02665 pgm->seen = 0;
02666 pgm->flagged = 0;
02667 pgm->unflagged = 1;
02668 } else if (box == OLD_FOLDER) {
02669 pgm->seen = 1;
02670 pgm->unseen = 0;
02671 }
02672
02673 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02674
02675 vms->vmArrayIndex = 0;
02676 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02677 vms->lastmsg = vms->vmArrayIndex - 1;
02678 mail_free_searchpgm(&pgm);
02679
02680
02681
02682
02683 if (box == 0 && !vms->dh_arraysize) {
02684 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02685 }
02686 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02687 ast_mutex_unlock(&vms->lock);
02688 return -1;
02689 }
02690
02691 ast_mutex_unlock(&vms->lock);
02692 return 0;
02693 }
02694
02695 static void write_file(char *filename, char *buffer, unsigned long len)
02696 {
02697 FILE *output;
02698
02699 output = fopen (filename, "w");
02700 if (fwrite(buffer, len, 1, output) != 1) {
02701 if (ferror(output)) {
02702 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02703 }
02704 }
02705 fclose (output);
02706 }
02707
02708 static void update_messages_by_imapuser(const char *user, unsigned long number)
02709 {
02710 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02711
02712 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02713 return;
02714 }
02715
02716 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02717
02718
02719 if (vms->vmArrayIndex >= vms->msg_array_max) {
02720 long *new_mem = ast_realloc(vms->msgArray, 2 * vms->msg_array_max * sizeof(long));
02721 if (!new_mem) {
02722 return;
02723 }
02724 vms->msgArray = new_mem;
02725 vms->msg_array_max *= 2;
02726 }
02727
02728 vms->msgArray[vms->vmArrayIndex++] = number;
02729 }
02730
02731 void mm_searched(MAILSTREAM *stream, unsigned long number)
02732 {
02733 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02734
02735 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02736 return;
02737
02738 update_messages_by_imapuser(user, number);
02739 }
02740
02741 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02742 {
02743 struct ast_variable *var;
02744 struct ast_vm_user *vmu;
02745
02746 vmu = ast_calloc(1, sizeof *vmu);
02747 if (!vmu)
02748 return NULL;
02749
02750 populate_defaults(vmu);
02751 ast_set_flag(vmu, VM_ALLOCED);
02752
02753 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02754 if (var) {
02755 apply_options_full(vmu, var);
02756 ast_variables_destroy(var);
02757 return vmu;
02758 } else {
02759 ast_free(vmu);
02760 return NULL;
02761 }
02762 }
02763
02764
02765
02766 void mm_exists(MAILSTREAM * stream, unsigned long number)
02767 {
02768
02769 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02770 if (number == 0) return;
02771 set_update(stream);
02772 }
02773
02774
02775 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02776 {
02777
02778 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02779 if (number == 0) return;
02780 set_update(stream);
02781 }
02782
02783
02784 void mm_flags(MAILSTREAM * stream, unsigned long number)
02785 {
02786
02787 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02788 if (number == 0) return;
02789 set_update(stream);
02790 }
02791
02792
02793 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02794 {
02795 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02796 mm_log (string, errflg);
02797 }
02798
02799
02800 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02801 {
02802 if (delimiter == '\0') {
02803 delimiter = delim;
02804 }
02805
02806 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02807 if (attributes & LATT_NOINFERIORS)
02808 ast_debug(5, "no inferiors\n");
02809 if (attributes & LATT_NOSELECT)
02810 ast_debug(5, "no select\n");
02811 if (attributes & LATT_MARKED)
02812 ast_debug(5, "marked\n");
02813 if (attributes & LATT_UNMARKED)
02814 ast_debug(5, "unmarked\n");
02815 }
02816
02817
02818 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02819 {
02820 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02821 if (attributes & LATT_NOINFERIORS)
02822 ast_debug(5, "no inferiors\n");
02823 if (attributes & LATT_NOSELECT)
02824 ast_debug(5, "no select\n");
02825 if (attributes & LATT_MARKED)
02826 ast_debug(5, "marked\n");
02827 if (attributes & LATT_UNMARKED)
02828 ast_debug(5, "unmarked\n");
02829 }
02830
02831
02832 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02833 {
02834 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02835 if (status->flags & SA_MESSAGES)
02836 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02837 if (status->flags & SA_RECENT)
02838 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02839 if (status->flags & SA_UNSEEN)
02840 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02841 if (status->flags & SA_UIDVALIDITY)
02842 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02843 if (status->flags & SA_UIDNEXT)
02844 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02845 ast_log(AST_LOG_NOTICE, "\n");
02846 }
02847
02848
02849 void mm_log(char *string, long errflg)
02850 {
02851 switch ((short) errflg) {
02852 case NIL:
02853 ast_debug(1, "IMAP Info: %s\n", string);
02854 break;
02855 case PARSE:
02856 case WARN:
02857 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02858 break;
02859 case ERROR:
02860 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02861 break;
02862 }
02863 }
02864
02865
02866 void mm_dlog(char *string)
02867 {
02868 ast_log(AST_LOG_NOTICE, "%s\n", string);
02869 }
02870
02871
02872 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02873 {
02874 struct ast_vm_user *vmu;
02875
02876 ast_debug(4, "Entering callback mm_login\n");
02877
02878 ast_copy_string(user, mb->user, MAILTMPLEN);
02879
02880
02881 if (!ast_strlen_zero(authpassword)) {
02882 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02883 } else {
02884 AST_LIST_TRAVERSE(&users, vmu, list) {
02885 if (!strcasecmp(mb->user, vmu->imapuser)) {
02886 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02887 break;
02888 }
02889 }
02890 if (!vmu) {
02891 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02892 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02893 free_user(vmu);
02894 }
02895 }
02896 }
02897 }
02898
02899
02900 void mm_critical(MAILSTREAM * stream)
02901 {
02902 }
02903
02904
02905 void mm_nocritical(MAILSTREAM * stream)
02906 {
02907 }
02908
02909
02910 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02911 {
02912 kill (getpid (), SIGSTOP);
02913 return NIL;
02914 }
02915
02916
02917 void mm_fatal(char *string)
02918 {
02919 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02920 }
02921
02922
02923 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02924 {
02925 struct vm_state *vms;
02926 char *mailbox = stream->mailbox, *user;
02927 char buf[1024] = "";
02928 unsigned long usage = 0, limit = 0;
02929
02930 while (pquota) {
02931 usage = pquota->usage;
02932 limit = pquota->limit;
02933 pquota = pquota->next;
02934 }
02935
02936 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)))) {
02937 ast_log(AST_LOG_ERROR, "No state found.\n");
02938 return;
02939 }
02940
02941 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02942
02943 vms->quota_usage = usage;
02944 vms->quota_limit = limit;
02945 }
02946
02947 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02948 {
02949 char *start, *eol_pnt;
02950 int taglen;
02951
02952 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02953 return NULL;
02954
02955 taglen = strlen(tag) + 1;
02956 if (taglen < 1)
02957 return NULL;
02958
02959 if (!(start = strstr(header, tag)))
02960 return NULL;
02961
02962
02963 memset(buf, 0, len);
02964
02965 ast_copy_string(buf, start+taglen, len);
02966 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02967 *eol_pnt = '\0';
02968 return buf;
02969 }
02970
02971 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02972 {
02973 char *start, *quote, *eol_pnt;
02974
02975 if (ast_strlen_zero(mailbox))
02976 return NULL;
02977
02978 if (!(start = strstr(mailbox, "/user=")))
02979 return NULL;
02980
02981 ast_copy_string(buf, start+6, len);
02982
02983 if (!(quote = strchr(buf, '\"'))) {
02984 if (!(eol_pnt = strchr(buf, '/')))
02985 eol_pnt = strchr(buf,'}');
02986 *eol_pnt = '\0';
02987 return buf;
02988 } else {
02989 eol_pnt = strchr(buf+1,'\"');
02990 *eol_pnt = '\0';
02991 return buf+1;
02992 }
02993 }
02994
02995 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02996 {
02997 struct vm_state *vms_p;
02998
02999 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03000 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
03001 return vms_p;
03002 }
03003 if (option_debug > 4)
03004 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
03005
03006 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
03007 return NULL;
03008 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
03009 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
03010 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03011 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03012 vms_p->mailstream = NIL;
03013 vms_p->imapversion = vmu->imapversion;
03014 if (option_debug > 4)
03015 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03016 vms_p->updated = 1;
03017
03018 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03019 init_vm_state(vms_p);
03020 vmstate_insert(vms_p);
03021 return vms_p;
03022 }
03023
03024 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03025 {
03026 struct vmstate *vlist = NULL;
03027
03028 if (interactive) {
03029 struct vm_state *vms;
03030 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03031 vms = pthread_getspecific(ts_vmstate.key);
03032 return vms;
03033 }
03034
03035 AST_LIST_LOCK(&vmstates);
03036 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03037 if (!vlist->vms) {
03038 ast_debug(3, "error: vms is NULL for %s\n", user);
03039 continue;
03040 }
03041 if (vlist->vms->imapversion != imapversion) {
03042 continue;
03043 }
03044 if (!vlist->vms->imapuser) {
03045 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03046 continue;
03047 }
03048
03049 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03050 AST_LIST_UNLOCK(&vmstates);
03051 return vlist->vms;
03052 }
03053 }
03054 AST_LIST_UNLOCK(&vmstates);
03055
03056 ast_debug(3, "%s not found in vmstates\n", user);
03057
03058 return NULL;
03059 }
03060
03061 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03062 {
03063
03064 struct vmstate *vlist = NULL;
03065 const char *local_context = S_OR(context, "default");
03066
03067 if (interactive) {
03068 struct vm_state *vms;
03069 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03070 vms = pthread_getspecific(ts_vmstate.key);
03071 return vms;
03072 }
03073
03074 AST_LIST_LOCK(&vmstates);
03075 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03076 if (!vlist->vms) {
03077 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03078 continue;
03079 }
03080 if (vlist->vms->imapversion != imapversion) {
03081 continue;
03082 }
03083 if (!vlist->vms->username || !vlist->vms->context) {
03084 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03085 continue;
03086 }
03087
03088 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);
03089
03090 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03091 ast_debug(3, "Found it!\n");
03092 AST_LIST_UNLOCK(&vmstates);
03093 return vlist->vms;
03094 }
03095 }
03096 AST_LIST_UNLOCK(&vmstates);
03097
03098 ast_debug(3, "%s not found in vmstates\n", mailbox);
03099
03100 return NULL;
03101 }
03102
03103 static void vmstate_insert(struct vm_state *vms)
03104 {
03105 struct vmstate *v;
03106 struct vm_state *altvms;
03107
03108
03109
03110
03111 if (vms->interactive == 1) {
03112 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03113 if (altvms) {
03114 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03115 vms->newmessages = altvms->newmessages;
03116 vms->oldmessages = altvms->oldmessages;
03117 vms->vmArrayIndex = altvms->vmArrayIndex;
03118
03119 vms->lastmsg = altvms->lastmsg;
03120 vms->curmsg = altvms->curmsg;
03121
03122 vms->persist_vms = altvms;
03123
03124 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03125 vms->mailstream = altvms->mailstream;
03126 #else
03127 vms->mailstream = NIL;
03128 #endif
03129 }
03130 return;
03131 }
03132
03133 if (!(v = ast_calloc(1, sizeof(*v))))
03134 return;
03135
03136 v->vms = vms;
03137
03138 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03139
03140 AST_LIST_LOCK(&vmstates);
03141 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03142 AST_LIST_UNLOCK(&vmstates);
03143 }
03144
03145 static void vmstate_delete(struct vm_state *vms)
03146 {
03147 struct vmstate *vc = NULL;
03148 struct vm_state *altvms = NULL;
03149
03150
03151
03152 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03153 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03154 altvms->newmessages = vms->newmessages;
03155 altvms->oldmessages = vms->oldmessages;
03156 altvms->updated = 1;
03157 vms->mailstream = mail_close(vms->mailstream);
03158
03159
03160 return;
03161 }
03162
03163 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03164
03165 AST_LIST_LOCK(&vmstates);
03166 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03167 if (vc->vms == vms) {
03168 AST_LIST_REMOVE_CURRENT(list);
03169 break;
03170 }
03171 }
03172 AST_LIST_TRAVERSE_SAFE_END
03173 AST_LIST_UNLOCK(&vmstates);
03174
03175 if (vc) {
03176 ast_mutex_destroy(&vc->vms->lock);
03177 ast_free(vc->vms->msgArray);
03178 vc->vms->msgArray = NULL;
03179 vc->vms->msg_array_max = 0;
03180
03181 ast_free(vc);
03182 } else {
03183 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03184 }
03185 }
03186
03187 static void set_update(MAILSTREAM * stream)
03188 {
03189 struct vm_state *vms;
03190 char *mailbox = stream->mailbox, *user;
03191 char buf[1024] = "";
03192
03193 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03194 if (user && option_debug > 2)
03195 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03196 return;
03197 }
03198
03199 ast_debug(3, "User %s mailbox set for update.\n", user);
03200
03201 vms->updated = 1;
03202 }
03203
03204 static void init_vm_state(struct vm_state *vms)
03205 {
03206 vms->msg_array_max = VMSTATE_MAX_MSG_ARRAY;
03207 vms->msgArray = ast_calloc(vms->msg_array_max, sizeof(long));
03208 if (!vms->msgArray) {
03209
03210 vms->msg_array_max = 0;
03211 }
03212 vms->vmArrayIndex = 0;
03213 ast_mutex_init(&vms->lock);
03214 }
03215
03216 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03217 {
03218 char *body_content;
03219 char *body_decoded;
03220 char *fn = is_intro ? vms->introfn : vms->fn;
03221 unsigned long len;
03222 unsigned long newlen;
03223 char filename[256];
03224
03225 if (!body || body == NIL)
03226 return -1;
03227
03228 ast_mutex_lock(&vms->lock);
03229 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03230 ast_mutex_unlock(&vms->lock);
03231 if (body_content != NIL) {
03232 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03233
03234 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03235
03236 if (!newlen) {
03237 return -1;
03238 }
03239 write_file(filename, (char *) body_decoded, newlen);
03240 } else {
03241 ast_debug(5, "Body of message is NULL.\n");
03242 return -1;
03243 }
03244 return 0;
03245 }
03246
03247
03248
03249
03250
03251
03252
03253
03254 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03255 char tmp[50];
03256 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03257 mail_list(stream, tmp, "*");
03258 }
03259
03260
03261
03262
03263
03264
03265
03266
03267 static void check_quota(struct vm_state *vms, char *mailbox) {
03268 ast_mutex_lock(&vms->lock);
03269 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03270 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03271 if (vms && vms->mailstream != NULL) {
03272 imap_getquotaroot(vms->mailstream, mailbox);
03273 } else {
03274 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03275 }
03276 ast_mutex_unlock(&vms->lock);
03277 }
03278
03279 #endif
03280
03281
03282
03283
03284
03285 static int vm_lock_path(const char *path)
03286 {
03287 switch (ast_lock_path(path)) {
03288 case AST_LOCK_TIMEOUT:
03289 return -1;
03290 default:
03291 return 0;
03292 }
03293 }
03294
03295
03296 #ifdef ODBC_STORAGE
03297 struct generic_prepare_struct {
03298 char *sql;
03299 int argc;
03300 char **argv;
03301 };
03302
03303 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03304 {
03305 struct generic_prepare_struct *gps = data;
03306 int res, i;
03307 SQLHSTMT stmt;
03308
03309 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03310 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03311 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03312 return NULL;
03313 }
03314 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03315 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03316 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03317 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03318 return NULL;
03319 }
03320 for (i = 0; i < gps->argc; i++)
03321 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03322
03323 return stmt;
03324 }
03325
03326
03327
03328
03329
03330
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340 static int retrieve_file(char *dir, int msgnum)
03341 {
03342 int x = 0;
03343 int res;
03344 int fd = -1;
03345 size_t fdlen = 0;
03346 void *fdm = MAP_FAILED;
03347 SQLSMALLINT colcount = 0;
03348 SQLHSTMT stmt;
03349 char sql[PATH_MAX];
03350 char fmt[80]="";
03351 char *c;
03352 char coltitle[256];
03353 SQLSMALLINT collen;
03354 SQLSMALLINT datatype;
03355 SQLSMALLINT decimaldigits;
03356 SQLSMALLINT nullable;
03357 SQLULEN colsize;
03358 SQLLEN colsize2;
03359 FILE *f = NULL;
03360 char rowdata[80];
03361 char fn[PATH_MAX];
03362 char full_fn[PATH_MAX];
03363 char msgnums[80];
03364 char *argv[] = { dir, msgnums };
03365 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03366
03367 struct odbc_obj *obj;
03368 obj = ast_odbc_request_obj(odbc_database, 0);
03369 if (obj) {
03370 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03371 c = strchr(fmt, '|');
03372 if (c)
03373 *c = '\0';
03374 if (!strcasecmp(fmt, "wav49"))
03375 strcpy(fmt, "WAV");
03376 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03377 if (msgnum > -1)
03378 make_file(fn, sizeof(fn), dir, msgnum);
03379 else
03380 ast_copy_string(fn, dir, sizeof(fn));
03381
03382
03383 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03384
03385 if (!(f = fopen(full_fn, "w+"))) {
03386 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03387 goto yuck;
03388 }
03389
03390 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03391 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03392 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03393 if (!stmt) {
03394 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03395 ast_odbc_release_obj(obj);
03396 goto yuck;
03397 }
03398 res = SQLFetch(stmt);
03399 if (res == SQL_NO_DATA) {
03400 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03401 ast_odbc_release_obj(obj);
03402 goto yuck;
03403 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03404 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03405 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03406 ast_odbc_release_obj(obj);
03407 goto yuck;
03408 }
03409 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03410 if (fd < 0) {
03411 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03412 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03413 ast_odbc_release_obj(obj);
03414 goto yuck;
03415 }
03416 res = SQLNumResultCols(stmt, &colcount);
03417 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03418 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03419 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03420 ast_odbc_release_obj(obj);
03421 goto yuck;
03422 }
03423 if (f)
03424 fprintf(f, "[message]\n");
03425 for (x = 0; x < colcount; x++) {
03426 rowdata[0] = '\0';
03427 colsize = 0;
03428 collen = sizeof(coltitle);
03429 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03430 &datatype, &colsize, &decimaldigits, &nullable);
03431 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03432 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03433 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03434 ast_odbc_release_obj(obj);
03435 goto yuck;
03436 }
03437 if (!strcasecmp(coltitle, "recording")) {
03438 off_t offset;
03439 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03440 fdlen = colsize2;
03441 if (fd > -1) {
03442 char tmp[1]="";
03443 lseek(fd, fdlen - 1, SEEK_SET);
03444 if (write(fd, tmp, 1) != 1) {
03445 close(fd);
03446 fd = -1;
03447 continue;
03448 }
03449
03450 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03451 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03452 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03453 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03454 ast_odbc_release_obj(obj);
03455 goto yuck;
03456 } else {
03457 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03458 munmap(fdm, CHUNKSIZE);
03459 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03460 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03461 unlink(full_fn);
03462 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03463 ast_odbc_release_obj(obj);
03464 goto yuck;
03465 }
03466 }
03467 }
03468 if (truncate(full_fn, fdlen) < 0) {
03469 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03470 }
03471 }
03472 } else {
03473 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03474 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03475 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03476 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03477 ast_odbc_release_obj(obj);
03478 goto yuck;
03479 }
03480 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03481 fprintf(f, "%s=%s\n", coltitle, rowdata);
03482 }
03483 }
03484 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03485 ast_odbc_release_obj(obj);
03486 } else
03487 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03488 yuck:
03489 if (f)
03490 fclose(f);
03491 if (fd > -1)
03492 close(fd);
03493 return x - 1;
03494 }
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504
03505
03506
03507 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03508 {
03509 int x = 0;
03510 int res;
03511 SQLHSTMT stmt;
03512 char sql[PATH_MAX];
03513 char rowdata[20];
03514 char *argv[] = { dir };
03515 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03516
03517 struct odbc_obj *obj;
03518 obj = ast_odbc_request_obj(odbc_database, 0);
03519 if (obj) {
03520 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03521
03522 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03523 if (!stmt) {
03524 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03525 ast_odbc_release_obj(obj);
03526 goto yuck;
03527 }
03528 res = SQLFetch(stmt);
03529 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03530 if (res == SQL_NO_DATA) {
03531 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03532 } else {
03533 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03534 }
03535
03536 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03537 ast_odbc_release_obj(obj);
03538 goto yuck;
03539 }
03540 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03541 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03542 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03543 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03544 ast_odbc_release_obj(obj);
03545 goto yuck;
03546 }
03547 if (sscanf(rowdata, "%30d", &x) != 1)
03548 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03549 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03550 ast_odbc_release_obj(obj);
03551 return x;
03552 } else
03553 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03554 yuck:
03555 return x - 1;
03556 }
03557
03558
03559
03560
03561
03562
03563
03564
03565
03566
03567 static int message_exists(char *dir, int msgnum)
03568 {
03569 int x = 0;
03570 int res;
03571 SQLHSTMT stmt;
03572 char sql[PATH_MAX];
03573 char rowdata[20];
03574 char msgnums[20];
03575 char *argv[] = { dir, msgnums };
03576 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03577
03578 struct odbc_obj *obj;
03579 obj = ast_odbc_request_obj(odbc_database, 0);
03580 if (obj) {
03581 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03582 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03583 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03584 if (!stmt) {
03585 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03586 ast_odbc_release_obj(obj);
03587 goto yuck;
03588 }
03589 res = SQLFetch(stmt);
03590 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03591 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03592 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03593 ast_odbc_release_obj(obj);
03594 goto yuck;
03595 }
03596 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03597 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03598 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03599 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03600 ast_odbc_release_obj(obj);
03601 goto yuck;
03602 }
03603 if (sscanf(rowdata, "%30d", &x) != 1)
03604 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03605 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03606 ast_odbc_release_obj(obj);
03607 } else
03608 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03609 yuck:
03610 return x;
03611 }
03612
03613
03614
03615
03616
03617
03618
03619
03620
03621
03622 static int count_messages(struct ast_vm_user *vmu, char *dir)
03623 {
03624 int x = 0;
03625 int res;
03626 SQLHSTMT stmt;
03627 char sql[PATH_MAX];
03628 char rowdata[20];
03629 char *argv[] = { dir };
03630 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03631
03632 struct odbc_obj *obj;
03633 obj = ast_odbc_request_obj(odbc_database, 0);
03634 if (obj) {
03635 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03636 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03637 if (!stmt) {
03638 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03639 ast_odbc_release_obj(obj);
03640 goto yuck;
03641 }
03642 res = SQLFetch(stmt);
03643 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03644 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03645 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03646 ast_odbc_release_obj(obj);
03647 goto yuck;
03648 }
03649 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03650 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03651 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03652 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03653 ast_odbc_release_obj(obj);
03654 goto yuck;
03655 }
03656 if (sscanf(rowdata, "%30d", &x) != 1)
03657 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03658 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03659 ast_odbc_release_obj(obj);
03660 return x;
03661 } else
03662 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03663 yuck:
03664 return x - 1;
03665
03666 }
03667
03668
03669
03670
03671
03672
03673
03674
03675
03676
03677
03678 static void delete_file(const char *sdir, int smsg)
03679 {
03680 SQLHSTMT stmt;
03681 char sql[PATH_MAX];
03682 char msgnums[20];
03683 char *argv[] = { NULL, msgnums };
03684 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03685 struct odbc_obj *obj;
03686
03687 argv[0] = ast_strdupa(sdir);
03688
03689 obj = ast_odbc_request_obj(odbc_database, 0);
03690 if (obj) {
03691 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03692 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03693 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03694 if (!stmt)
03695 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03696 else
03697 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03698 ast_odbc_release_obj(obj);
03699 } else
03700 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03701 return;
03702 }
03703
03704
03705
03706
03707
03708
03709
03710
03711
03712
03713
03714
03715 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03716 {
03717 SQLHSTMT stmt;
03718 char sql[512];
03719 char msgnums[20];
03720 char msgnumd[20];
03721 struct odbc_obj *obj;
03722 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03723 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03724
03725 delete_file(ddir, dmsg);
03726 obj = ast_odbc_request_obj(odbc_database, 0);
03727 if (obj) {
03728 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03729 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03730 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);
03731 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03732 if (!stmt)
03733 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03734 else
03735 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03736 ast_odbc_release_obj(obj);
03737 } else
03738 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03739 return;
03740 }
03741
03742 struct insert_data {
03743 char *sql;
03744 const char *dir;
03745 const char *msgnums;
03746 void *data;
03747 SQLLEN datalen;
03748 SQLLEN indlen;
03749 const char *context;
03750 const char *macrocontext;
03751 const char *callerid;
03752 const char *origtime;
03753 const char *duration;
03754 const char *mailboxuser;
03755 const char *mailboxcontext;
03756 const char *category;
03757 const char *flag;
03758 };
03759
03760 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03761 {
03762 struct insert_data *data = vdata;
03763 int res;
03764 SQLHSTMT stmt;
03765
03766 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03767 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03768 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03769 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03770 return NULL;
03771 }
03772
03773 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03774 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03775 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03776 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03777 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03778 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03779 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03780 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03781 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03782 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03783 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03784 if (!ast_strlen_zero(data->category)) {
03785 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03786 }
03787 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03788 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03789 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03790 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03791 return NULL;
03792 }
03793
03794 return stmt;
03795 }
03796
03797
03798
03799
03800
03801
03802
03803
03804
03805
03806
03807
03808
03809
03810 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03811 {
03812 int res = 0;
03813 int fd = -1;
03814 void *fdm = MAP_FAILED;
03815 off_t fdlen = -1;
03816 SQLHSTMT stmt;
03817 char sql[PATH_MAX];
03818 char msgnums[20];
03819 char fn[PATH_MAX];
03820 char full_fn[PATH_MAX];
03821 char fmt[80]="";
03822 char *c;
03823 struct ast_config *cfg = NULL;
03824 struct odbc_obj *obj;
03825 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03826 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03827 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03828
03829 delete_file(dir, msgnum);
03830 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03831 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03832 return -1;
03833 }
03834
03835 do {
03836 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03837 c = strchr(fmt, '|');
03838 if (c)
03839 *c = '\0';
03840 if (!strcasecmp(fmt, "wav49"))
03841 strcpy(fmt, "WAV");
03842 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03843 if (msgnum > -1)
03844 make_file(fn, sizeof(fn), dir, msgnum);
03845 else
03846 ast_copy_string(fn, dir, sizeof(fn));
03847 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03848 cfg = ast_config_load(full_fn, config_flags);
03849 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03850 fd = open(full_fn, O_RDWR);
03851 if (fd < 0) {
03852 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03853 res = -1;
03854 break;
03855 }
03856 if (valid_config(cfg)) {
03857 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03858 idata.context = "";
03859 }
03860 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03861 idata.macrocontext = "";
03862 }
03863 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03864 idata.callerid = "";
03865 }
03866 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03867 idata.origtime = "";
03868 }
03869 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03870 idata.duration = "";
03871 }
03872 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03873 idata.category = "";
03874 }
03875 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03876 idata.flag = "";
03877 }
03878 }
03879 fdlen = lseek(fd, 0, SEEK_END);
03880 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03881 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03882 res = -1;
03883 break;
03884 }
03885 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03886 if (fdm == MAP_FAILED) {
03887 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03888 res = -1;
03889 break;
03890 }
03891 idata.data = fdm;
03892 idata.datalen = idata.indlen = fdlen;
03893
03894 if (!ast_strlen_zero(idata.category))
03895 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03896 else
03897 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03898
03899 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03900 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03901 } else {
03902 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03903 res = -1;
03904 }
03905 } while (0);
03906 if (obj) {
03907 ast_odbc_release_obj(obj);
03908 }
03909 if (valid_config(cfg))
03910 ast_config_destroy(cfg);
03911 if (fdm != MAP_FAILED)
03912 munmap(fdm, fdlen);
03913 if (fd > -1)
03914 close(fd);
03915 return res;
03916 }
03917
03918
03919
03920
03921
03922
03923
03924
03925
03926
03927
03928
03929
03930
03931 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03932 {
03933 SQLHSTMT stmt;
03934 char sql[PATH_MAX];
03935 char msgnums[20];
03936 char msgnumd[20];
03937 struct odbc_obj *obj;
03938 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03939 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03940
03941 delete_file(ddir, dmsg);
03942 obj = ast_odbc_request_obj(odbc_database, 0);
03943 if (obj) {
03944 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03945 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03946 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03947 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03948 if (!stmt)
03949 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03950 else
03951 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03952 ast_odbc_release_obj(obj);
03953 } else
03954 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03955 return;
03956 }
03957
03958
03959
03960
03961
03962
03963
03964
03965
03966
03967
03968
03969 static int remove_file(char *dir, int msgnum)
03970 {
03971 char fn[PATH_MAX];
03972 char full_fn[PATH_MAX];
03973 char msgnums[80];
03974
03975 if (msgnum > -1) {
03976 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03977 make_file(fn, sizeof(fn), dir, msgnum);
03978 } else
03979 ast_copy_string(fn, dir, sizeof(fn));
03980 ast_filedelete(fn, NULL);
03981 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03982 unlink(full_fn);
03983 return 0;
03984 }
03985 #else
03986 #ifndef IMAP_STORAGE
03987
03988
03989
03990
03991
03992
03993
03994
03995
03996 static int count_messages(struct ast_vm_user *vmu, char *dir)
03997 {
03998
03999 int vmcount = 0;
04000 DIR *vmdir = NULL;
04001 struct dirent *vment = NULL;
04002
04003 if (vm_lock_path(dir))
04004 return ERROR_LOCK_PATH;
04005
04006 if ((vmdir = opendir(dir))) {
04007 while ((vment = readdir(vmdir))) {
04008 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
04009 vmcount++;
04010 }
04011 }
04012 closedir(vmdir);
04013 }
04014 ast_unlock_path(dir);
04015
04016 return vmcount;
04017 }
04018
04019
04020
04021
04022
04023
04024
04025
04026 static void rename_file(char *sfn, char *dfn)
04027 {
04028 char stxt[PATH_MAX];
04029 char dtxt[PATH_MAX];
04030 ast_filerename(sfn, dfn, NULL);
04031 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04032 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04033 if (ast_check_realtime("voicemail_data")) {
04034 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04035 }
04036 rename(stxt, dtxt);
04037 }
04038
04039
04040
04041
04042
04043
04044
04045
04046
04047
04048
04049
04050 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04051 {
04052 int x;
04053 unsigned char map[MAXMSGLIMIT] = "";
04054 DIR *msgdir;
04055 struct dirent *msgdirent;
04056 int msgdirint;
04057 char extension[4];
04058 int stopcount = 0;
04059
04060
04061
04062
04063
04064 if (!(msgdir = opendir(dir))) {
04065 return -1;
04066 }
04067
04068 while ((msgdirent = readdir(msgdir))) {
04069 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04070 map[msgdirint] = 1;
04071 stopcount++;
04072 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04073 }
04074 }
04075 closedir(msgdir);
04076
04077 for (x = 0; x < vmu->maxmsg; x++) {
04078 if (map[x] == 1) {
04079 stopcount--;
04080 } else if (map[x] == 0 && !stopcount) {
04081 break;
04082 }
04083 }
04084
04085 return x - 1;
04086 }
04087
04088 #endif
04089 #endif
04090 #ifndef IMAP_STORAGE
04091
04092
04093
04094
04095
04096
04097
04098
04099
04100
04101 static int copy(char *infile, char *outfile)
04102 {
04103 int ifd;
04104 int ofd;
04105 int res;
04106 int len;
04107 char buf[4096];
04108
04109 #ifdef HARDLINK_WHEN_POSSIBLE
04110
04111 if (link(infile, outfile)) {
04112 #endif
04113 if ((ifd = open(infile, O_RDONLY)) < 0) {
04114 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04115 return -1;
04116 }
04117 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04118 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04119 close(ifd);
04120 return -1;
04121 }
04122 do {
04123 len = read(ifd, buf, sizeof(buf));
04124 if (len < 0) {
04125 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04126 close(ifd);
04127 close(ofd);
04128 unlink(outfile);
04129 } else if (len) {
04130 res = write(ofd, buf, len);
04131 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04132 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04133 close(ifd);
04134 close(ofd);
04135 unlink(outfile);
04136 }
04137 }
04138 } while (len);
04139 close(ifd);
04140 close(ofd);
04141 return 0;
04142 #ifdef HARDLINK_WHEN_POSSIBLE
04143 } else {
04144
04145 return 0;
04146 }
04147 #endif
04148 }
04149
04150
04151
04152
04153
04154
04155
04156
04157
04158
04159 static void copy_plain_file(char *frompath, char *topath)
04160 {
04161 char frompath2[PATH_MAX], topath2[PATH_MAX];
04162 struct ast_variable *tmp,*var = NULL;
04163 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04164 ast_filecopy(frompath, topath, NULL);
04165 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04166 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04167 if (ast_check_realtime("voicemail_data")) {
04168 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04169
04170 for (tmp = var; tmp; tmp = tmp->next) {
04171 if (!strcasecmp(tmp->name, "origmailbox")) {
04172 origmailbox = tmp->value;
04173 } else if (!strcasecmp(tmp->name, "context")) {
04174 context = tmp->value;
04175 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04176 macrocontext = tmp->value;
04177 } else if (!strcasecmp(tmp->name, "exten")) {
04178 exten = tmp->value;
04179 } else if (!strcasecmp(tmp->name, "priority")) {
04180 priority = tmp->value;
04181 } else if (!strcasecmp(tmp->name, "callerchan")) {
04182 callerchan = tmp->value;
04183 } else if (!strcasecmp(tmp->name, "callerid")) {
04184 callerid = tmp->value;
04185 } else if (!strcasecmp(tmp->name, "origdate")) {
04186 origdate = tmp->value;
04187 } else if (!strcasecmp(tmp->name, "origtime")) {
04188 origtime = tmp->value;
04189 } else if (!strcasecmp(tmp->name, "category")) {
04190 category = tmp->value;
04191 } else if (!strcasecmp(tmp->name, "duration")) {
04192 duration = tmp->value;
04193 }
04194 }
04195 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);
04196 }
04197 copy(frompath2, topath2);
04198 ast_variables_destroy(var);
04199 }
04200 #endif
04201
04202
04203
04204
04205
04206
04207
04208
04209
04210 static int vm_delete(char *file)
04211 {
04212 char *txt;
04213 int txtsize = 0;
04214
04215 txtsize = (strlen(file) + 5)*sizeof(char);
04216 txt = ast_alloca(txtsize);
04217
04218
04219
04220 if (ast_check_realtime("voicemail_data")) {
04221 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04222 }
04223 snprintf(txt, txtsize, "%s.txt", file);
04224 unlink(txt);
04225 return ast_filedelete(file, NULL);
04226 }
04227
04228
04229
04230
04231 static int inbuf(struct baseio *bio, FILE *fi)
04232 {
04233 int l;
04234
04235 if (bio->ateof)
04236 return 0;
04237
04238 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04239 if (ferror(fi))
04240 return -1;
04241
04242 bio->ateof = 1;
04243 return 0;
04244 }
04245
04246 bio->iolen = l;
04247 bio->iocp = 0;
04248
04249 return 1;
04250 }
04251
04252
04253
04254
04255 static int inchar(struct baseio *bio, FILE *fi)
04256 {
04257 if (bio->iocp>=bio->iolen) {
04258 if (!inbuf(bio, fi))
04259 return EOF;
04260 }
04261
04262 return bio->iobuf[bio->iocp++];
04263 }
04264
04265
04266
04267
04268 static int ochar(struct baseio *bio, int c, FILE *so)
04269 {
04270 if (bio->linelength >= BASELINELEN) {
04271 if (fputs(ENDL, so) == EOF) {
04272 return -1;
04273 }
04274
04275 bio->linelength = 0;
04276 }
04277
04278 if (putc(((unsigned char) c), so) == EOF) {
04279 return -1;
04280 }
04281
04282 bio->linelength++;
04283
04284 return 1;
04285 }
04286
04287
04288
04289
04290
04291
04292
04293
04294
04295
04296 static int base_encode(char *filename, FILE *so)
04297 {
04298 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04299 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04300 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04301 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04302 int i, hiteof = 0;
04303 FILE *fi;
04304 struct baseio bio;
04305
04306 memset(&bio, 0, sizeof(bio));
04307 bio.iocp = BASEMAXINLINE;
04308
04309 if (!(fi = fopen(filename, "rb"))) {
04310 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04311 return -1;
04312 }
04313
04314 while (!hiteof){
04315 unsigned char igroup[3], ogroup[4];
04316 int c, n;
04317
04318 memset(igroup, 0, sizeof(igroup));
04319
04320 for (n = 0; n < 3; n++) {
04321 if ((c = inchar(&bio, fi)) == EOF) {
04322 hiteof = 1;
04323 break;
04324 }
04325
04326 igroup[n] = (unsigned char) c;
04327 }
04328
04329 if (n > 0) {
04330 ogroup[0]= dtable[igroup[0] >> 2];
04331 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04332 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04333 ogroup[3]= dtable[igroup[2] & 0x3F];
04334
04335 if (n < 3) {
04336 ogroup[3] = '=';
04337
04338 if (n < 2)
04339 ogroup[2] = '=';
04340 }
04341
04342 for (i = 0; i < 4; i++)
04343 ochar(&bio, ogroup[i], so);
04344 }
04345 }
04346
04347 fclose(fi);
04348
04349 if (fputs(ENDL, so) == EOF) {
04350 return 0;
04351 }
04352
04353 return 1;
04354 }
04355
04356 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)
04357 {
04358 char callerid[256];
04359 char num[12];
04360 char fromdir[256], fromfile[256];
04361 struct ast_config *msg_cfg;
04362 const char *origcallerid, *origtime;
04363 char origcidname[80], origcidnum[80], origdate[80];
04364 int inttime;
04365 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04366
04367
04368 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04369 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04370 snprintf(num, sizeof(num), "%d", msgnum);
04371 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04372 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04373 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04374 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04375 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04376 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04377 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04378 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04379 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04380 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04381
04382
04383 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04384 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04385 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04386 strcat(fromfile, ".txt");
04387 }
04388 if (!(msg_cfg = ast_config_load(fromfile, config_flags)) || !(valid_config(msg_cfg))) {
04389 if (option_debug > 0) {
04390 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04391 }
04392 return;
04393 }
04394
04395 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04396 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04397 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04398 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04399 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04400 }
04401
04402 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04403 struct timeval tv = { inttime, };
04404 struct ast_tm tm;
04405 ast_localtime(&tv, &tm, NULL);
04406 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04407 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04408 }
04409 ast_config_destroy(msg_cfg);
04410 }
04411
04412
04413
04414
04415
04416
04417
04418
04419
04420 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04421 {
04422 const char *ptr;
04423
04424
04425 ast_str_set(buf, maxlen, "\"");
04426 for (ptr = from; *ptr; ptr++) {
04427 if (*ptr == '"' || *ptr == '\\') {
04428 ast_str_append(buf, maxlen, "\\%c", *ptr);
04429 } else {
04430 ast_str_append(buf, maxlen, "%c", *ptr);
04431 }
04432 }
04433 ast_str_append(buf, maxlen, "\"");
04434
04435 return ast_str_buffer(*buf);
04436 }
04437
04438
04439
04440
04441
04442 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04443 {
04444 const struct vm_zone *z = NULL;
04445 struct timeval t = ast_tvnow();
04446
04447
04448 if (!ast_strlen_zero(vmu->zonetag)) {
04449
04450 AST_LIST_LOCK(&zones);
04451 AST_LIST_TRAVERSE(&zones, z, list) {
04452 if (!strcmp(z->name, vmu->zonetag))
04453 break;
04454 }
04455 AST_LIST_UNLOCK(&zones);
04456 }
04457 ast_localtime(&t, tm, z ? z->timezone : NULL);
04458 return tm;
04459 }
04460
04461
04462
04463
04464
04465 static int check_mime(const char *str)
04466 {
04467 for (; *str; str++) {
04468 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04469 return 1;
04470 }
04471 }
04472 return 0;
04473 }
04474
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484
04485
04486
04487
04488
04489
04490
04491
04492 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04493 {
04494 struct ast_str *tmp = ast_str_alloca(80);
04495 int first_section = 1;
04496
04497 ast_str_reset(*end);
04498 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04499 for (; *start; start++) {
04500 int need_encoding = 0;
04501 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04502 need_encoding = 1;
04503 }
04504 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04505 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04506 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04507 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04508
04509 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04510 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04511 first_section = 0;
04512 }
04513 if (need_encoding && *start == ' ') {
04514 ast_str_append(&tmp, -1, "_");
04515 } else if (need_encoding) {
04516 ast_str_append(&tmp, -1, "=%hhX", *start);
04517 } else {
04518 ast_str_append(&tmp, -1, "%c", *start);
04519 }
04520 }
04521 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04522 return ast_str_buffer(*end);
04523 }
04524
04525
04526
04527
04528
04529
04530
04531
04532
04533
04534
04535
04536
04537
04538
04539
04540
04541
04542
04543
04544
04545
04546
04547
04548 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)
04549 {
04550 char date[256];
04551 char host[MAXHOSTNAMELEN] = "";
04552 char who[256];
04553 char bound[256];
04554 char dur[256];
04555 struct ast_tm tm;
04556 char enc_cidnum[256] = "", enc_cidname[256] = "";
04557 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04558 char *greeting_attachment;
04559 char filename[256];
04560
04561 if (!str1 || !str2) {
04562 ast_free(str1);
04563 ast_free(str2);
04564 return;
04565 }
04566
04567 if (cidnum) {
04568 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04569 }
04570 if (cidname) {
04571 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04572 }
04573 gethostname(host, sizeof(host) - 1);
04574
04575 if (strchr(srcemail, '@')) {
04576 ast_copy_string(who, srcemail, sizeof(who));
04577 } else {
04578 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04579 }
04580
04581 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04582 if (greeting_attachment) {
04583 *greeting_attachment++ = '\0';
04584 }
04585
04586 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04587 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04588 fprintf(p, "Date: %s" ENDL, date);
04589
04590
04591 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04592
04593 if (!ast_strlen_zero(fromstring)) {
04594 struct ast_channel *ast;
04595 if ((ast = ast_dummy_channel_alloc())) {
04596 char *ptr;
04597 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04598 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04599
04600 if (check_mime(ast_str_buffer(str1))) {
04601 int first_line = 1;
04602 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04603 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04604 *ptr = '\0';
04605 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04606 first_line = 0;
04607
04608 ast_str_set(&str2, 0, "%s", ptr + 1);
04609 }
04610 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04611 } else {
04612 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
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 {
04619 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04620 }
04621
04622 if (check_mime(vmu->fullname)) {
04623 int first_line = 1;
04624 char *ptr;
04625 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04626 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04627 *ptr = '\0';
04628 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04629 first_line = 0;
04630
04631 ast_str_set(&str2, 0, "%s", ptr + 1);
04632 }
04633 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04634 } else {
04635 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04636 }
04637
04638 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04639 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04640 struct ast_channel *ast;
04641 if ((ast = ast_dummy_channel_alloc())) {
04642 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04643 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04644 if (check_mime(ast_str_buffer(str1))) {
04645 int first_line = 1;
04646 char *ptr;
04647 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04648 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04649 *ptr = '\0';
04650 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04651 first_line = 0;
04652
04653 ast_str_set(&str2, 0, "%s", ptr + 1);
04654 }
04655 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04656 } else {
04657 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04658 }
04659 ast = ast_channel_unref(ast);
04660 } else {
04661 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04662 }
04663 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04664 if (ast_strlen_zero(flag)) {
04665 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04666 } else {
04667 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04668 }
04669 } else {
04670 if (ast_strlen_zero(flag)) {
04671 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04672 } else {
04673 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04674 }
04675 }
04676
04677 fprintf(p, "Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
04678 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04679 if (imap) {
04680
04681 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04682
04683 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04684 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04685 #ifdef IMAP_STORAGE
04686 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04687 #else
04688 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04689 #endif
04690
04691 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04692 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04693 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04694 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04695 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04696 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04697 if (!ast_strlen_zero(category)) {
04698 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04699 } else {
04700 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04701 }
04702 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04703 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04704 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04705 }
04706 if (!ast_strlen_zero(cidnum)) {
04707 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04708 }
04709 if (!ast_strlen_zero(cidname)) {
04710 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04711 }
04712 fprintf(p, "MIME-Version: 1.0" ENDL);
04713 if (attach_user_voicemail) {
04714
04715 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%u", msgnum + 1, mailbox,
04716 (int) getpid(), (unsigned int) ast_random());
04717
04718 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04719 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04720 fprintf(p, "--%s" ENDL, bound);
04721 }
04722 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04723 if (emailbody || vmu->emailbody) {
04724 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04725 struct ast_channel *ast;
04726 if ((ast = ast_dummy_channel_alloc())) {
04727 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04728 ast_str_substitute_variables(&str1, 0, ast, e_body);
04729 #ifdef IMAP_STORAGE
04730 {
04731
04732 char *line = ast_str_buffer(str1), *next;
04733 do {
04734
04735 if ((next = strchr(line, '\n'))) {
04736 *next++ = '\0';
04737 }
04738 fprintf(p, "%s" ENDL, line);
04739 line = next;
04740 } while (!ast_strlen_zero(line));
04741 }
04742 #else
04743 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04744 #endif
04745 ast = ast_channel_unref(ast);
04746 } else {
04747 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04748 }
04749 } else if (msgnum > -1) {
04750 if (strcmp(vmu->mailbox, mailbox)) {
04751
04752 struct ast_config *msg_cfg;
04753 const char *v;
04754 int inttime;
04755 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04756 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04757
04758 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04759 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04760 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04761 strcat(fromfile, ".txt");
04762 }
04763 if ((msg_cfg = ast_config_load(fromfile, config_flags)) && valid_config(msg_cfg)) {
04764 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04765 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04766 }
04767
04768
04769
04770 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04771 struct timeval tv = { inttime, };
04772 struct ast_tm tm;
04773 ast_localtime(&tv, &tm, NULL);
04774 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04775 }
04776 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04777 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04778 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04779 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04780 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04781 date, origcallerid, origdate);
04782 ast_config_destroy(msg_cfg);
04783 } else {
04784 goto plain_message;
04785 }
04786 } else {
04787 plain_message:
04788 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04789 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04790 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04791 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04792 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04793 }
04794 } else {
04795 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04796 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04797 }
04798
04799 if (imap || attach_user_voicemail) {
04800 if (!ast_strlen_zero(attach2)) {
04801 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04802 ast_debug(5, "creating second attachment filename %s\n", filename);
04803 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04804 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04805 ast_debug(5, "creating attachment filename %s\n", filename);
04806 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04807 } else {
04808 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04809 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04810 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04811 }
04812 }
04813 ast_free(str1);
04814 ast_free(str2);
04815 }
04816
04817 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)
04818 {
04819 char tmpdir[256], newtmp[256];
04820 char fname[256];
04821 char tmpcmd[256];
04822 int tmpfd = -1;
04823 int soxstatus = 0;
04824
04825
04826 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04827
04828 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04829 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04830 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04831 tmpfd = mkstemp(newtmp);
04832 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04833 ast_debug(3, "newtmp: %s\n", newtmp);
04834 if (tmpfd > -1) {
04835 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04836 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04837 attach = newtmp;
04838 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04839 } else {
04840 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04841 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04842 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04843 }
04844 }
04845 }
04846 fprintf(p, "--%s" ENDL, bound);
04847 if (msgnum > -1)
04848 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04849 else
04850 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04851 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04852 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04853 if (msgnum > -1)
04854 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04855 else
04856 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04857 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04858 base_encode(fname, p);
04859 if (last)
04860 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04861 if (tmpfd > -1) {
04862 if (soxstatus == 0) {
04863 unlink(fname);
04864 }
04865 close(tmpfd);
04866 unlink(newtmp);
04867 }
04868 return 0;
04869 }
04870
04871 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)
04872 {
04873 FILE *p = NULL;
04874 char tmp[80] = "/tmp/astmail-XXXXXX";
04875 char tmp2[256];
04876 char *stringp;
04877
04878 if (vmu && ast_strlen_zero(vmu->email)) {
04879 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04880 return(0);
04881 }
04882
04883
04884 format = ast_strdupa(format);
04885 stringp = format;
04886 strsep(&stringp, "|");
04887
04888 if (!strcmp(format, "wav49"))
04889 format = "WAV";
04890 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %u\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04891
04892
04893 if ((p = vm_mkftemp(tmp)) == NULL) {
04894 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04895 return -1;
04896 } else {
04897 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04898 fclose(p);
04899 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04900 ast_safe_system(tmp2);
04901 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04902 }
04903 return 0;
04904 }
04905
04906 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)
04907 {
04908 char enc_cidnum[256], enc_cidname[256];
04909 char date[256];
04910 char host[MAXHOSTNAMELEN] = "";
04911 char who[256];
04912 char dur[PATH_MAX];
04913 char tmp[80] = "/tmp/astmail-XXXXXX";
04914 char tmp2[PATH_MAX];
04915 struct ast_tm tm;
04916 FILE *p;
04917 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04918
04919 if (!str1 || !str2) {
04920 ast_free(str1);
04921 ast_free(str2);
04922 return -1;
04923 }
04924
04925 if (cidnum) {
04926 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04927 }
04928 if (cidname) {
04929 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04930 }
04931
04932 if ((p = vm_mkftemp(tmp)) == NULL) {
04933 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04934 ast_free(str1);
04935 ast_free(str2);
04936 return -1;
04937 }
04938 gethostname(host, sizeof(host)-1);
04939 if (strchr(srcemail, '@')) {
04940 ast_copy_string(who, srcemail, sizeof(who));
04941 } else {
04942 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04943 }
04944 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04945 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04946 fprintf(p, "Date: %s\n", date);
04947
04948
04949 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04950
04951 if (!ast_strlen_zero(pagerfromstring)) {
04952 struct ast_channel *ast;
04953 if ((ast = ast_dummy_channel_alloc())) {
04954 char *ptr;
04955 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04956 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04957
04958 if (check_mime(ast_str_buffer(str1))) {
04959 int first_line = 1;
04960 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04961 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04962 *ptr = '\0';
04963 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04964 first_line = 0;
04965
04966 ast_str_set(&str2, 0, "%s", ptr + 1);
04967 }
04968 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04969 } else {
04970 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04971 }
04972 ast = ast_channel_unref(ast);
04973 } else {
04974 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04975 }
04976 } else {
04977 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04978 }
04979
04980 if (check_mime(vmu->fullname)) {
04981 int first_line = 1;
04982 char *ptr;
04983 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04984 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04985 *ptr = '\0';
04986 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04987 first_line = 0;
04988
04989 ast_str_set(&str2, 0, "%s", ptr + 1);
04990 }
04991 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04992 } else {
04993 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04994 }
04995
04996 if (!ast_strlen_zero(pagersubject)) {
04997 struct ast_channel *ast;
04998 if ((ast = ast_dummy_channel_alloc())) {
04999 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05000 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
05001 if (check_mime(ast_str_buffer(str1))) {
05002 int first_line = 1;
05003 char *ptr;
05004 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
05005 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05006 *ptr = '\0';
05007 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05008 first_line = 0;
05009
05010 ast_str_set(&str2, 0, "%s", ptr + 1);
05011 }
05012 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05013 } else {
05014 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
05015 }
05016 ast = ast_channel_unref(ast);
05017 } else {
05018 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05019 }
05020 } else {
05021 if (ast_strlen_zero(flag)) {
05022 fprintf(p, "Subject: New VM\n\n");
05023 } else {
05024 fprintf(p, "Subject: New %s VM\n\n", flag);
05025 }
05026 }
05027
05028 if (pagerbody) {
05029 struct ast_channel *ast;
05030 if ((ast = ast_dummy_channel_alloc())) {
05031 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05032 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05033 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05034 ast = ast_channel_unref(ast);
05035 } else {
05036 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05037 }
05038 } else {
05039 fprintf(p, "New %s long %s msg in box %s\n"
05040 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05041 }
05042
05043 fclose(p);
05044 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05045 ast_safe_system(tmp2);
05046 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05047 ast_free(str1);
05048 ast_free(str2);
05049 return 0;
05050 }
05051
05052
05053
05054
05055
05056
05057
05058
05059
05060
05061 static int get_date(char *s, int len)
05062 {
05063 struct ast_tm tm;
05064 struct timeval t = ast_tvnow();
05065
05066 ast_localtime(&t, &tm, "UTC");
05067
05068 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05069 }
05070
05071 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05072 {
05073 int res;
05074 char fn[PATH_MAX];
05075 char dest[PATH_MAX];
05076
05077 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05078
05079 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05080 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05081 return -1;
05082 }
05083
05084 RETRIEVE(fn, -1, ext, context);
05085 if (ast_fileexists(fn, NULL, NULL) > 0) {
05086 res = ast_stream_and_wait(chan, fn, ecodes);
05087 if (res) {
05088 DISPOSE(fn, -1);
05089 return res;
05090 }
05091 } else {
05092
05093 DISPOSE(fn, -1);
05094 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05095 if (res)
05096 return res;
05097 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05098 if (res)
05099 return res;
05100 }
05101 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05102 return res;
05103 }
05104
05105 static void free_zone(struct vm_zone *z)
05106 {
05107 ast_free(z);
05108 }
05109
05110 #ifdef ODBC_STORAGE
05111 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05112 {
05113 int x = -1;
05114 int res;
05115 SQLHSTMT stmt = NULL;
05116 char sql[PATH_MAX];
05117 char rowdata[20];
05118 char tmp[PATH_MAX] = "";
05119 struct odbc_obj *obj = NULL;
05120 char *context;
05121 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05122
05123 if (newmsgs)
05124 *newmsgs = 0;
05125 if (oldmsgs)
05126 *oldmsgs = 0;
05127 if (urgentmsgs)
05128 *urgentmsgs = 0;
05129
05130
05131 if (ast_strlen_zero(mailbox))
05132 return 0;
05133
05134 ast_copy_string(tmp, mailbox, sizeof(tmp));
05135
05136 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05137 int u, n, o;
05138 char *next, *remaining = tmp;
05139 while ((next = strsep(&remaining, " ,"))) {
05140 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05141 return -1;
05142 }
05143 if (urgentmsgs) {
05144 *urgentmsgs += u;
05145 }
05146 if (newmsgs) {
05147 *newmsgs += n;
05148 }
05149 if (oldmsgs) {
05150 *oldmsgs += o;
05151 }
05152 }
05153 return 0;
05154 }
05155
05156 context = strchr(tmp, '@');
05157 if (context) {
05158 *context = '\0';
05159 context++;
05160 } else
05161 context = "default";
05162
05163 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05164 do {
05165 if (newmsgs) {
05166 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05167 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05168 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05169 break;
05170 }
05171 res = SQLFetch(stmt);
05172 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05173 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05174 break;
05175 }
05176 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05177 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05178 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05179 break;
05180 }
05181 *newmsgs = atoi(rowdata);
05182 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05183 }
05184
05185 if (oldmsgs) {
05186 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05187 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05188 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05189 break;
05190 }
05191 res = SQLFetch(stmt);
05192 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05193 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05194 break;
05195 }
05196 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05197 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05198 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05199 break;
05200 }
05201 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05202 *oldmsgs = atoi(rowdata);
05203 }
05204
05205 if (urgentmsgs) {
05206 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05207 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05208 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05209 break;
05210 }
05211 res = SQLFetch(stmt);
05212 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05213 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05214 break;
05215 }
05216 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05217 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05218 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05219 break;
05220 }
05221 *urgentmsgs = atoi(rowdata);
05222 }
05223
05224 x = 0;
05225 } while (0);
05226 } else {
05227 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05228 }
05229
05230 if (stmt) {
05231 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05232 }
05233 if (obj) {
05234 ast_odbc_release_obj(obj);
05235 }
05236 return x;
05237 }
05238
05239
05240
05241
05242
05243
05244
05245
05246
05247
05248 static int messagecount(const char *context, const char *mailbox, const char *folder)
05249 {
05250 struct odbc_obj *obj = NULL;
05251 int nummsgs = 0;
05252 int res;
05253 SQLHSTMT stmt = NULL;
05254 char sql[PATH_MAX];
05255 char rowdata[20];
05256 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05257 if (!folder)
05258 folder = "INBOX";
05259
05260 if (ast_strlen_zero(mailbox))
05261 return 0;
05262
05263 obj = ast_odbc_request_obj(odbc_database, 0);
05264 if (obj) {
05265 if (!strcmp(folder, "INBOX")) {
05266 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);
05267 } else {
05268 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05269 }
05270 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05271 if (!stmt) {
05272 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05273 goto yuck;
05274 }
05275 res = SQLFetch(stmt);
05276 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05277 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05278 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05279 goto yuck;
05280 }
05281 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05282 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05283 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05284 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05285 goto yuck;
05286 }
05287 nummsgs = atoi(rowdata);
05288 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05289 } else
05290 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05291
05292 yuck:
05293 if (obj)
05294 ast_odbc_release_obj(obj);
05295 return nummsgs;
05296 }
05297
05298
05299
05300
05301
05302
05303
05304
05305
05306 static int has_voicemail(const char *mailbox, const char *folder)
05307 {
05308 char tmp[256], *tmp2 = tmp, *box, *context;
05309 ast_copy_string(tmp, mailbox, sizeof(tmp));
05310 while ((context = box = strsep(&tmp2, ",&"))) {
05311 strsep(&context, "@");
05312 if (ast_strlen_zero(context))
05313 context = "default";
05314 if (messagecount(context, box, folder))
05315 return 1;
05316 }
05317 return 0;
05318 }
05319 #endif
05320 #ifndef IMAP_STORAGE
05321
05322
05323
05324
05325
05326
05327
05328
05329
05330
05331
05332
05333
05334
05335
05336
05337 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)
05338 {
05339 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05340 const char *frombox = mbox(vmu, imbox);
05341 const char *userfolder;
05342 int recipmsgnum;
05343 int res = 0;
05344
05345 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05346
05347 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05348 userfolder = "Urgent";
05349 } else {
05350 userfolder = "INBOX";
05351 }
05352
05353 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05354
05355 if (!dir)
05356 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05357 else
05358 ast_copy_string(fromdir, dir, sizeof(fromdir));
05359
05360 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05361 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05362
05363 if (vm_lock_path(todir))
05364 return ERROR_LOCK_PATH;
05365
05366 recipmsgnum = last_message_index(recip, todir) + 1;
05367 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05368 make_file(topath, sizeof(topath), todir, recipmsgnum);
05369 #ifndef ODBC_STORAGE
05370 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05371 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05372 } else {
05373 #endif
05374
05375
05376
05377 copy_plain_file(frompath, topath);
05378 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05379 vm_delete(topath);
05380 #ifndef ODBC_STORAGE
05381 }
05382 #endif
05383 } else {
05384 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05385 res = -1;
05386 }
05387 ast_unlock_path(todir);
05388 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05389 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05390 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05391 flag);
05392
05393 return res;
05394 }
05395 #endif
05396 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05397
05398 static int messagecount(const char *context, const char *mailbox, const char *folder)
05399 {
05400 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05401 }
05402
05403 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05404 {
05405 DIR *dir;
05406 struct dirent *de;
05407 char fn[256];
05408 int ret = 0;
05409
05410
05411 if (ast_strlen_zero(mailbox))
05412 return 0;
05413
05414 if (ast_strlen_zero(folder))
05415 folder = "INBOX";
05416 if (ast_strlen_zero(context))
05417 context = "default";
05418
05419 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05420
05421 if (!(dir = opendir(fn)))
05422 return 0;
05423
05424 while ((de = readdir(dir))) {
05425 if (!strncasecmp(de->d_name, "msg", 3)) {
05426 if (shortcircuit) {
05427 ret = 1;
05428 break;
05429 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05430 ret++;
05431 }
05432 }
05433 }
05434
05435 closedir(dir);
05436
05437 return ret;
05438 }
05439
05440
05441
05442
05443
05444
05445
05446
05447
05448
05449 static int has_voicemail(const char *mailbox, const char *folder)
05450 {
05451 char tmp[256], *tmp2 = tmp, *box, *context;
05452 ast_copy_string(tmp, mailbox, sizeof(tmp));
05453 if (ast_strlen_zero(folder)) {
05454 folder = "INBOX";
05455 }
05456 while ((box = strsep(&tmp2, ",&"))) {
05457 if ((context = strchr(box, '@')))
05458 *context++ = '\0';
05459 else
05460 context = "default";
05461 if (__has_voicemail(context, box, folder, 1))
05462 return 1;
05463
05464 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05465 return 1;
05466 }
05467 }
05468 return 0;
05469 }
05470
05471
05472 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05473 {
05474 char tmp[256];
05475 char *context;
05476
05477
05478 if (ast_strlen_zero(mailbox))
05479 return 0;
05480
05481 if (newmsgs)
05482 *newmsgs = 0;
05483 if (oldmsgs)
05484 *oldmsgs = 0;
05485 if (urgentmsgs)
05486 *urgentmsgs = 0;
05487
05488 if (strchr(mailbox, ',')) {
05489 int tmpnew, tmpold, tmpurgent;
05490 char *mb, *cur;
05491
05492 ast_copy_string(tmp, mailbox, sizeof(tmp));
05493 mb = tmp;
05494 while ((cur = strsep(&mb, ", "))) {
05495 if (!ast_strlen_zero(cur)) {
05496 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05497 return -1;
05498 else {
05499 if (newmsgs)
05500 *newmsgs += tmpnew;
05501 if (oldmsgs)
05502 *oldmsgs += tmpold;
05503 if (urgentmsgs)
05504 *urgentmsgs += tmpurgent;
05505 }
05506 }
05507 }
05508 return 0;
05509 }
05510
05511 ast_copy_string(tmp, mailbox, sizeof(tmp));
05512
05513 if ((context = strchr(tmp, '@')))
05514 *context++ = '\0';
05515 else
05516 context = "default";
05517
05518 if (newmsgs)
05519 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05520 if (oldmsgs)
05521 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05522 if (urgentmsgs)
05523 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05524
05525 return 0;
05526 }
05527
05528 #endif
05529
05530
05531 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05532 {
05533 int urgentmsgs = 0;
05534 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05535 if (newmsgs) {
05536 *newmsgs += urgentmsgs;
05537 }
05538 return res;
05539 }
05540
05541 static void run_externnotify(char *context, char *extension, const char *flag)
05542 {
05543 char arguments[255];
05544 char ext_context[256] = "";
05545 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05546 struct ast_smdi_mwi_message *mwi_msg;
05547
05548 if (!ast_strlen_zero(context))
05549 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05550 else
05551 ast_copy_string(ext_context, extension, sizeof(ext_context));
05552
05553 if (smdi_iface) {
05554 if (ast_app_has_voicemail(ext_context, NULL))
05555 ast_smdi_mwi_set(smdi_iface, extension);
05556 else
05557 ast_smdi_mwi_unset(smdi_iface, extension);
05558
05559 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05560 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05561 if (!strncmp(mwi_msg->cause, "INV", 3))
05562 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05563 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05564 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05565 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05566 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05567 } else {
05568 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05569 }
05570 }
05571
05572 if (!ast_strlen_zero(externnotify)) {
05573 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05574 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05575 } else {
05576 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &",
05577 externnotify, S_OR(context, "\"\""),
05578 extension, newvoicemails,
05579 oldvoicemails, urgentvoicemails);
05580 ast_debug(1, "Executing %s\n", arguments);
05581 ast_safe_system(arguments);
05582 }
05583 }
05584 }
05585
05586
05587
05588
05589
05590
05591 struct leave_vm_options {
05592 unsigned int flags;
05593 signed char record_gain;
05594 char *exitcontext;
05595 };
05596
05597
05598
05599
05600
05601
05602
05603
05604
05605
05606
05607 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05608 {
05609 #ifdef IMAP_STORAGE
05610 int newmsgs, oldmsgs;
05611 #else
05612 char urgdir[PATH_MAX];
05613 #endif
05614 char txtfile[PATH_MAX];
05615 char tmptxtfile[PATH_MAX];
05616 struct vm_state *vms = NULL;
05617 char callerid[256];
05618 FILE *txt;
05619 char date[256];
05620 int txtdes;
05621 int res = 0;
05622 int msgnum;
05623 int duration = 0;
05624 int sound_duration = 0;
05625 int ausemacro = 0;
05626 int ousemacro = 0;
05627 int ouseexten = 0;
05628 char tmpdur[16];
05629 char priority[16];
05630 char origtime[16];
05631 char dir[PATH_MAX];
05632 char tmpdir[PATH_MAX];
05633 char fn[PATH_MAX];
05634 char prefile[PATH_MAX] = "";
05635 char tempfile[PATH_MAX] = "";
05636 char ext_context[256] = "";
05637 char fmt[80];
05638 char *context;
05639 char ecodes[17] = "#";
05640 struct ast_str *tmp = ast_str_create(16);
05641 char *tmpptr;
05642 struct ast_vm_user *vmu;
05643 struct ast_vm_user svm;
05644 const char *category = NULL;
05645 const char *code;
05646 const char *alldtmf = "0123456789ABCD*#";
05647 char flag[80];
05648
05649 if (!tmp) {
05650 return -1;
05651 }
05652
05653 ast_str_set(&tmp, 0, "%s", ext);
05654 ext = ast_str_buffer(tmp);
05655 if ((context = strchr(ext, '@'))) {
05656 *context++ = '\0';
05657 tmpptr = strchr(context, '&');
05658 } else {
05659 tmpptr = strchr(ext, '&');
05660 }
05661
05662 if (tmpptr)
05663 *tmpptr++ = '\0';
05664
05665 ast_channel_lock(chan);
05666 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05667 category = ast_strdupa(category);
05668 }
05669 ast_channel_unlock(chan);
05670
05671 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05672 ast_copy_string(flag, "Urgent", sizeof(flag));
05673 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05674 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05675 } else {
05676 flag[0] = '\0';
05677 }
05678
05679 ast_debug(3, "Before find_user\n");
05680 if (!(vmu = find_user(&svm, context, ext))) {
05681 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05682 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05683 ast_free(tmp);
05684 return res;
05685 }
05686
05687 if (strcmp(vmu->context, "default"))
05688 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05689 else
05690 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05691
05692
05693
05694
05695
05696
05697 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05698 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05699 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05700 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05701 }
05702
05703
05704
05705
05706 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05707 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05708 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05709 ast_free(tmp);
05710 return -1;
05711 }
05712 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05713 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05714 ast_copy_string(prefile, tempfile, sizeof(prefile));
05715
05716 DISPOSE(tempfile, -1);
05717
05718 #ifndef IMAP_STORAGE
05719 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05720 #else
05721 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05722 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05723 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05724 }
05725 #endif
05726
05727
05728 if (ast_test_flag(vmu, VM_OPERATOR)) {
05729 if (!ast_strlen_zero(vmu->exit)) {
05730 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05731 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05732 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05733 ouseexten = 1;
05734 }
05735 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05736 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05737 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05738 ouseexten = 1;
05739 } else if (!ast_strlen_zero(chan->macrocontext)
05740 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05741 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05742 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05743 ousemacro = 1;
05744 }
05745 }
05746
05747 if (!ast_strlen_zero(vmu->exit)) {
05748 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05749 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05750 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05751 }
05752 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05753 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05754 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05755 } else if (!ast_strlen_zero(chan->macrocontext)
05756 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05757 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05758 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05759 ausemacro = 1;
05760 }
05761
05762 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05763 for (code = alldtmf; *code; code++) {
05764 char e[2] = "";
05765 e[0] = *code;
05766 if (strchr(ecodes, e[0]) == NULL
05767 && ast_canmatch_extension(chan,
05768 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05769 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05770 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05771 }
05772 }
05773 }
05774
05775
05776 if (!ast_strlen_zero(prefile)) {
05777 #ifdef ODBC_STORAGE
05778 int success =
05779 #endif
05780 RETRIEVE(prefile, -1, ext, context);
05781 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05782 if (ast_streamfile(chan, prefile, chan->language) > -1)
05783 res = ast_waitstream(chan, ecodes);
05784 #ifdef ODBC_STORAGE
05785 if (success == -1) {
05786
05787 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05788 store_file(prefile, vmu->mailbox, vmu->context, -1);
05789 }
05790 #endif
05791 } else {
05792 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05793 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05794 }
05795 DISPOSE(prefile, -1);
05796 if (res < 0) {
05797 ast_debug(1, "Hang up during prefile playback\n");
05798 free_user(vmu);
05799 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05800 ast_free(tmp);
05801 return -1;
05802 }
05803 }
05804 if (res == '#') {
05805
05806 ast_set_flag(options, OPT_SILENT);
05807 res = 0;
05808 }
05809
05810 if (vmu->maxmsg == 0) {
05811 if (option_debug > 2)
05812 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05813 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05814 goto leave_vm_out;
05815 }
05816 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05817 res = ast_stream_and_wait(chan, INTRO, ecodes);
05818 if (res == '#') {
05819 ast_set_flag(options, OPT_SILENT);
05820 res = 0;
05821 }
05822 }
05823 if (res > 0)
05824 ast_stopstream(chan);
05825
05826
05827 if (res == '*') {
05828 chan->exten[0] = 'a';
05829 chan->exten[1] = '\0';
05830 if (!ast_strlen_zero(vmu->exit)) {
05831 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05832 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05833 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05834 }
05835 chan->priority = 0;
05836 free_user(vmu);
05837 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05838 ast_free(tmp);
05839 return 0;
05840 }
05841
05842
05843 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05844 transfer:
05845 if (ouseexten || ousemacro) {
05846 chan->exten[0] = 'o';
05847 chan->exten[1] = '\0';
05848 if (!ast_strlen_zero(vmu->exit)) {
05849 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05850 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05851 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05852 }
05853 ast_play_and_wait(chan, "transfer");
05854 chan->priority = 0;
05855 free_user(vmu);
05856 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05857 }
05858 ast_free(tmp);
05859 return OPERATOR_EXIT;
05860 }
05861
05862
05863 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05864 if (!ast_strlen_zero(options->exitcontext)) {
05865 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05866 }
05867 free_user(vmu);
05868 ast_free(tmp);
05869 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05870 return res;
05871 }
05872
05873 if (res < 0) {
05874 free_user(vmu);
05875 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05876 ast_free(tmp);
05877 return -1;
05878 }
05879
05880 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05881 if (!ast_strlen_zero(fmt)) {
05882 msgnum = 0;
05883
05884 #ifdef IMAP_STORAGE
05885
05886
05887 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05888 if (res < 0) {
05889 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05890 ast_free(tmp);
05891 return -1;
05892 }
05893 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05894
05895
05896
05897
05898 if (!(vms = create_vm_state_from_user(vmu))) {
05899 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05900 ast_free(tmp);
05901 return -1;
05902 }
05903 }
05904 vms->newmessages++;
05905
05906
05907 msgnum = newmsgs + oldmsgs;
05908 ast_debug(3, "Messagecount set to %d\n", msgnum);
05909 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05910
05911 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05912
05913 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05914 goto leave_vm_out;
05915 }
05916 #else
05917 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05918 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05919 if (!res)
05920 res = ast_waitstream(chan, "");
05921 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05922 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05923 inprocess_count(vmu->mailbox, vmu->context, -1);
05924 goto leave_vm_out;
05925 }
05926
05927 #endif
05928 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05929 txtdes = mkstemp(tmptxtfile);
05930 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05931 if (txtdes < 0) {
05932 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05933 if (!res)
05934 res = ast_waitstream(chan, "");
05935 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05936 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05937 inprocess_count(vmu->mailbox, vmu->context, -1);
05938 goto leave_vm_out;
05939 }
05940
05941
05942 if (res >= 0) {
05943
05944 res = ast_stream_and_wait(chan, "beep", "");
05945 }
05946
05947
05948 if (ast_check_realtime("voicemail_data")) {
05949 snprintf(priority, sizeof(priority), "%d", chan->priority);
05950 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05951 get_date(date, sizeof(date));
05952 ast_callerid_merge(callerid, sizeof(callerid),
05953 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05954 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05955 "Unknown");
05956 ast_store_realtime("voicemail_data",
05957 "origmailbox", ext,
05958 "context", chan->context,
05959 "macrocontext", chan->macrocontext,
05960 "exten", chan->exten,
05961 "priority", priority,
05962 "callerchan", chan->name,
05963 "callerid", callerid,
05964 "origdate", date,
05965 "origtime", origtime,
05966 "category", S_OR(category, ""),
05967 "filename", tmptxtfile,
05968 SENTINEL);
05969 }
05970
05971
05972 txt = fdopen(txtdes, "w+");
05973 if (txt) {
05974 get_date(date, sizeof(date));
05975 ast_callerid_merge(callerid, sizeof(callerid),
05976 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05977 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05978 "Unknown");
05979 fprintf(txt,
05980 ";\n"
05981 "; Message Information file\n"
05982 ";\n"
05983 "[message]\n"
05984 "origmailbox=%s\n"
05985 "context=%s\n"
05986 "macrocontext=%s\n"
05987 "exten=%s\n"
05988 "rdnis=%s\n"
05989 "priority=%d\n"
05990 "callerchan=%s\n"
05991 "callerid=%s\n"
05992 "origdate=%s\n"
05993 "origtime=%ld\n"
05994 "category=%s\n",
05995 ext,
05996 chan->context,
05997 chan->macrocontext,
05998 chan->exten,
05999 S_COR(chan->redirecting.from.number.valid,
06000 chan->redirecting.from.number.str, "unknown"),
06001 chan->priority,
06002 chan->name,
06003 callerid,
06004 date, (long) time(NULL),
06005 category ? category : "");
06006 } else {
06007 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
06008 inprocess_count(vmu->mailbox, vmu->context, -1);
06009 if (ast_check_realtime("voicemail_data")) {
06010 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06011 }
06012 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
06013 goto leave_vm_out;
06014 }
06015 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
06016
06017 if (txt) {
06018 fprintf(txt, "flag=%s\n", flag);
06019 if (sound_duration < vmu->minsecs) {
06020 fclose(txt);
06021 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06022 ast_filedelete(tmptxtfile, NULL);
06023 unlink(tmptxtfile);
06024 if (ast_check_realtime("voicemail_data")) {
06025 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06026 }
06027 inprocess_count(vmu->mailbox, vmu->context, -1);
06028 } else {
06029 fprintf(txt, "duration=%d\n", duration);
06030 fclose(txt);
06031 if (vm_lock_path(dir)) {
06032 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06033
06034 ast_filedelete(tmptxtfile, NULL);
06035 unlink(tmptxtfile);
06036 inprocess_count(vmu->mailbox, vmu->context, -1);
06037 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06038 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06039 unlink(tmptxtfile);
06040 ast_unlock_path(dir);
06041 inprocess_count(vmu->mailbox, vmu->context, -1);
06042 if (ast_check_realtime("voicemail_data")) {
06043 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06044 }
06045 } else {
06046 #ifndef IMAP_STORAGE
06047 msgnum = last_message_index(vmu, dir) + 1;
06048 #endif
06049 make_file(fn, sizeof(fn), dir, msgnum);
06050
06051
06052 #ifndef IMAP_STORAGE
06053 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06054 #else
06055 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06056 #endif
06057
06058 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06059 ast_filerename(tmptxtfile, fn, NULL);
06060 rename(tmptxtfile, txtfile);
06061 inprocess_count(vmu->mailbox, vmu->context, -1);
06062
06063
06064
06065 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06066 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06067
06068 ast_unlock_path(dir);
06069 if (ast_check_realtime("voicemail_data")) {
06070 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06071 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06072 }
06073
06074
06075
06076 if (ast_fileexists(fn, NULL, NULL) > 0) {
06077 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06078 }
06079
06080
06081 while (tmpptr) {
06082 struct ast_vm_user recipu, *recip;
06083 char *exten, *cntx;
06084
06085 exten = strsep(&tmpptr, "&");
06086 cntx = strchr(exten, '@');
06087 if (cntx) {
06088 *cntx = '\0';
06089 cntx++;
06090 }
06091 if ((recip = find_user(&recipu, cntx, exten))) {
06092 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06093 free_user(recip);
06094 }
06095 }
06096 #ifndef IMAP_STORAGE
06097 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06098
06099 char sfn[PATH_MAX];
06100 char dfn[PATH_MAX];
06101 int x;
06102
06103 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06104 x = last_message_index(vmu, urgdir) + 1;
06105 make_file(sfn, sizeof(sfn), dir, msgnum);
06106 make_file(dfn, sizeof(dfn), urgdir, x);
06107 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06108 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06109
06110 ast_copy_string(fn, dfn, sizeof(fn));
06111 msgnum = x;
06112 }
06113 #endif
06114
06115 if (ast_fileexists(fn, NULL, NULL)) {
06116 #ifdef IMAP_STORAGE
06117 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06118 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06119 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06120 flag);
06121 #else
06122 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06123 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06124 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06125 flag);
06126 #endif
06127 }
06128
06129
06130 if (ast_fileexists(fn, NULL, NULL)) {
06131 DISPOSE(dir, msgnum);
06132 }
06133 }
06134 }
06135 } else {
06136 inprocess_count(vmu->mailbox, vmu->context, -1);
06137 }
06138 if (res == '0') {
06139 goto transfer;
06140 } else if (res > 0 && res != 't')
06141 res = 0;
06142
06143 if (sound_duration < vmu->minsecs)
06144
06145 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06146 else
06147 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06148 } else
06149 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06150 leave_vm_out:
06151 free_user(vmu);
06152
06153 #ifdef IMAP_STORAGE
06154
06155 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06156 if (expungeonhangup == 1) {
06157 ast_mutex_lock(&vms->lock);
06158 #ifdef HAVE_IMAP_TK2006
06159 if (LEVELUIDPLUS (vms->mailstream)) {
06160 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06161 } else
06162 #endif
06163 mail_expunge(vms->mailstream);
06164 ast_mutex_unlock(&vms->lock);
06165 }
06166 #endif
06167
06168 ast_free(tmp);
06169 return res;
06170 }
06171
06172 #if !defined(IMAP_STORAGE)
06173 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06174 {
06175
06176
06177 int x, dest;
06178 char sfn[PATH_MAX];
06179 char dfn[PATH_MAX];
06180
06181 if (vm_lock_path(dir)) {
06182 return ERROR_LOCK_PATH;
06183 }
06184
06185 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06186 make_file(sfn, sizeof(sfn), dir, x);
06187 if (EXISTS(dir, x, sfn, NULL)) {
06188
06189 if (x != dest) {
06190 make_file(dfn, sizeof(dfn), dir, dest);
06191 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06192 }
06193
06194 dest++;
06195 }
06196 }
06197 ast_unlock_path(dir);
06198
06199 return dest;
06200 }
06201 #endif
06202
06203 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06204 {
06205 int d;
06206 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06207 return d;
06208 }
06209
06210 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06211 {
06212 #ifdef IMAP_STORAGE
06213
06214
06215 char sequence[10];
06216 char mailbox[256];
06217 int res;
06218
06219
06220 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06221
06222 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06223 ast_mutex_lock(&vms->lock);
06224
06225 if (box == OLD_FOLDER) {
06226 mail_setflag(vms->mailstream, sequence, "\\Seen");
06227 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06228 } else if (box == NEW_FOLDER) {
06229 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06230 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06231 }
06232 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06233 ast_mutex_unlock(&vms->lock);
06234 return 0;
06235 }
06236
06237 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06238 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06239 if (mail_create(vms->mailstream, mailbox) == NIL)
06240 ast_debug(5, "Folder exists.\n");
06241 else
06242 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06243 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06244 ast_mutex_unlock(&vms->lock);
06245 return res;
06246 #else
06247 char *dir = vms->curdir;
06248 char *username = vms->username;
06249 char *context = vmu->context;
06250 char sfn[PATH_MAX];
06251 char dfn[PATH_MAX];
06252 char ddir[PATH_MAX];
06253 const char *dbox = mbox(vmu, box);
06254 int x, i;
06255 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06256
06257 if (vm_lock_path(ddir))
06258 return ERROR_LOCK_PATH;
06259
06260 x = last_message_index(vmu, ddir) + 1;
06261
06262 if (box == 10 && x >= vmu->maxdeletedmsg) {
06263 x--;
06264 for (i = 1; i <= x; i++) {
06265
06266 make_file(sfn, sizeof(sfn), ddir, i);
06267 make_file(dfn, sizeof(dfn), ddir, i - 1);
06268 if (EXISTS(ddir, i, sfn, NULL)) {
06269 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06270 } else
06271 break;
06272 }
06273 } else {
06274 if (x >= vmu->maxmsg) {
06275 ast_unlock_path(ddir);
06276 return -1;
06277 }
06278 }
06279 make_file(sfn, sizeof(sfn), dir, msg);
06280 make_file(dfn, sizeof(dfn), ddir, x);
06281 if (strcmp(sfn, dfn)) {
06282 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06283 }
06284 ast_unlock_path(ddir);
06285 #endif
06286 return 0;
06287 }
06288
06289 static int adsi_logo(unsigned char *buf)
06290 {
06291 int bytes = 0;
06292 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06293 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06294 return bytes;
06295 }
06296
06297 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06298 {
06299 unsigned char buf[256];
06300 int bytes = 0;
06301 int x;
06302 char num[5];
06303
06304 *useadsi = 0;
06305 bytes += ast_adsi_data_mode(buf + bytes);
06306 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06307
06308 bytes = 0;
06309 bytes += adsi_logo(buf);
06310 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06311 #ifdef DISPLAY
06312 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06313 #endif
06314 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06315 bytes += ast_adsi_data_mode(buf + bytes);
06316 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06317
06318 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06319 bytes = 0;
06320 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06321 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06322 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06323 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06324 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06325 return 0;
06326 }
06327
06328 #ifdef DISPLAY
06329
06330 bytes = 0;
06331 bytes += ast_adsi_logo(buf);
06332 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06333 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06334 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06335 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06336 #endif
06337 bytes = 0;
06338 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06339 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06340 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06341 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06342 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06343 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06344 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06345
06346 #ifdef DISPLAY
06347
06348 bytes = 0;
06349 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06350 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06351
06352 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06353 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06354 #endif
06355
06356 bytes = 0;
06357
06358 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06359 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06360 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06361 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06362 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06363 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06364 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06365
06366 #ifdef DISPLAY
06367
06368 bytes = 0;
06369 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06370 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06371 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06372 #endif
06373
06374 bytes = 0;
06375 for (x = 0; x < 5; x++) {
06376 snprintf(num, sizeof(num), "%d", x);
06377 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06378 }
06379 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06380 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06381
06382 #ifdef DISPLAY
06383
06384 bytes = 0;
06385 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06386 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06387 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06388 #endif
06389
06390 if (ast_adsi_end_download(chan)) {
06391 bytes = 0;
06392 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06393 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06394 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06395 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06396 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06397 return 0;
06398 }
06399 bytes = 0;
06400 bytes += ast_adsi_download_disconnect(buf + bytes);
06401 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06402 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06403
06404 ast_debug(1, "Done downloading scripts...\n");
06405
06406 #ifdef DISPLAY
06407
06408 bytes = 0;
06409 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06410 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06411 #endif
06412 ast_debug(1, "Restarting session...\n");
06413
06414 bytes = 0;
06415
06416 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06417 *useadsi = 1;
06418 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06419 } else
06420 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06421
06422 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06423 return 0;
06424 }
06425
06426 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06427 {
06428 int x;
06429 if (!ast_adsi_available(chan))
06430 return;
06431 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06432 if (x < 0)
06433 return;
06434 if (!x) {
06435 if (adsi_load_vmail(chan, useadsi)) {
06436 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06437 return;
06438 }
06439 } else
06440 *useadsi = 1;
06441 }
06442
06443 static void adsi_login(struct ast_channel *chan)
06444 {
06445 unsigned char buf[256];
06446 int bytes = 0;
06447 unsigned char keys[8];
06448 int x;
06449 if (!ast_adsi_available(chan))
06450 return;
06451
06452 for (x = 0; x < 8; x++)
06453 keys[x] = 0;
06454
06455 keys[3] = ADSI_KEY_APPS + 3;
06456
06457 bytes += adsi_logo(buf + bytes);
06458 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06459 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06460 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06461 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06462 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06463 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06464 bytes += ast_adsi_set_keys(buf + bytes, keys);
06465 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06466 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06467 }
06468
06469 static void adsi_password(struct ast_channel *chan)
06470 {
06471 unsigned char buf[256];
06472 int bytes = 0;
06473 unsigned char keys[8];
06474 int x;
06475 if (!ast_adsi_available(chan))
06476 return;
06477
06478 for (x = 0; x < 8; x++)
06479 keys[x] = 0;
06480
06481 keys[3] = ADSI_KEY_APPS + 3;
06482
06483 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06484 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06485 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06486 bytes += ast_adsi_set_keys(buf + bytes, keys);
06487 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06488 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06489 }
06490
06491 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06492 {
06493 unsigned char buf[256];
06494 int bytes = 0;
06495 unsigned char keys[8];
06496 int x, y;
06497
06498 if (!ast_adsi_available(chan))
06499 return;
06500
06501 for (x = 0; x < 5; x++) {
06502 y = ADSI_KEY_APPS + 12 + start + x;
06503 if (y > ADSI_KEY_APPS + 12 + 4)
06504 y = 0;
06505 keys[x] = ADSI_KEY_SKT | y;
06506 }
06507 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06508 keys[6] = 0;
06509 keys[7] = 0;
06510
06511 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06512 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06513 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06514 bytes += ast_adsi_set_keys(buf + bytes, keys);
06515 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06516
06517 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06518 }
06519
06520 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06521 {
06522 int bytes = 0;
06523 unsigned char buf[256];
06524 char buf1[256], buf2[256];
06525 char fn2[PATH_MAX];
06526
06527 char cid[256] = "";
06528 char *val;
06529 char *name, *num;
06530 char datetime[21] = "";
06531 FILE *f;
06532
06533 unsigned char keys[8];
06534
06535 int x;
06536
06537 if (!ast_adsi_available(chan))
06538 return;
06539
06540
06541 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06542 f = fopen(fn2, "r");
06543 if (f) {
06544 while (!feof(f)) {
06545 if (!fgets((char *) buf, sizeof(buf), f)) {
06546 continue;
06547 }
06548 if (!feof(f)) {
06549 char *stringp = NULL;
06550 stringp = (char *) buf;
06551 strsep(&stringp, "=");
06552 val = strsep(&stringp, "=");
06553 if (!ast_strlen_zero(val)) {
06554 if (!strcmp((char *) buf, "callerid"))
06555 ast_copy_string(cid, val, sizeof(cid));
06556 if (!strcmp((char *) buf, "origdate"))
06557 ast_copy_string(datetime, val, sizeof(datetime));
06558 }
06559 }
06560 }
06561 fclose(f);
06562 }
06563
06564 for (x = 0; x < 5; x++)
06565 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06566 keys[6] = 0x0;
06567 keys[7] = 0x0;
06568
06569 if (!vms->curmsg) {
06570
06571 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06572 }
06573 if (vms->curmsg >= vms->lastmsg) {
06574
06575 if (vms->curmsg) {
06576
06577 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06578 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06579
06580 } else {
06581
06582 keys[3] = 1;
06583 }
06584 }
06585
06586 if (!ast_strlen_zero(cid)) {
06587 ast_callerid_parse(cid, &name, &num);
06588 if (!name)
06589 name = num;
06590 } else
06591 name = "Unknown Caller";
06592
06593
06594 #ifdef IMAP_STORAGE
06595 ast_mutex_lock(&vms->lock);
06596 #endif
06597 if (vms->deleted[vms->curmsg]) {
06598 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06599 }
06600 #ifdef IMAP_STORAGE
06601 ast_mutex_unlock(&vms->lock);
06602 #endif
06603
06604
06605 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06606 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06607 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06608 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06609
06610 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06611 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06612 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06613 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06614 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06615 bytes += ast_adsi_set_keys(buf + bytes, keys);
06616 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06617
06618 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06619 }
06620
06621 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06622 {
06623 int bytes = 0;
06624 unsigned char buf[256];
06625 unsigned char keys[8];
06626
06627 int x;
06628
06629 if (!ast_adsi_available(chan))
06630 return;
06631
06632
06633 for (x = 0; x < 5; x++)
06634 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06635
06636 keys[6] = 0x0;
06637 keys[7] = 0x0;
06638
06639 if (!vms->curmsg) {
06640
06641 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06642 }
06643 if (vms->curmsg >= vms->lastmsg) {
06644
06645 if (vms->curmsg) {
06646
06647 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06648 } else {
06649
06650 keys[3] = 1;
06651 }
06652 }
06653
06654
06655 #ifdef IMAP_STORAGE
06656 ast_mutex_lock(&vms->lock);
06657 #endif
06658 if (vms->deleted[vms->curmsg]) {
06659 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06660 }
06661 #ifdef IMAP_STORAGE
06662 ast_mutex_unlock(&vms->lock);
06663 #endif
06664
06665
06666 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06667 bytes += ast_adsi_set_keys(buf + bytes, keys);
06668 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06669
06670 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06671 }
06672
06673 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06674 {
06675 unsigned char buf[256] = "";
06676 char buf1[256] = "", buf2[256] = "";
06677 int bytes = 0;
06678 unsigned char keys[8];
06679 int x;
06680
06681 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06682 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06683 if (!ast_adsi_available(chan))
06684 return;
06685 if (vms->newmessages) {
06686 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06687 if (vms->oldmessages) {
06688 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06689 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06690 } else {
06691 snprintf(buf2, sizeof(buf2), "%s.", newm);
06692 }
06693 } else if (vms->oldmessages) {
06694 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06695 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06696 } else {
06697 strcpy(buf1, "You have no messages.");
06698 buf2[0] = ' ';
06699 buf2[1] = '\0';
06700 }
06701 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06702 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06703 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06704
06705 for (x = 0; x < 6; x++)
06706 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06707 keys[6] = 0;
06708 keys[7] = 0;
06709
06710
06711 if (vms->lastmsg < 0)
06712 keys[0] = 1;
06713 bytes += ast_adsi_set_keys(buf + bytes, keys);
06714
06715 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06716
06717 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06718 }
06719
06720 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06721 {
06722 unsigned char buf[256] = "";
06723 char buf1[256] = "", buf2[256] = "";
06724 int bytes = 0;
06725 unsigned char keys[8];
06726 int x;
06727
06728 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06729
06730 if (!ast_adsi_available(chan))
06731 return;
06732
06733
06734 for (x = 0; x < 6; x++)
06735 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06736
06737 keys[6] = 0;
06738 keys[7] = 0;
06739
06740 if ((vms->lastmsg + 1) < 1)
06741 keys[0] = 0;
06742
06743 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06744 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06745
06746 if (vms->lastmsg + 1)
06747 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06748 else
06749 strcpy(buf2, "no messages.");
06750 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06751 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06752 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06753 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06754 bytes += ast_adsi_set_keys(buf + bytes, keys);
06755
06756 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06757
06758 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06759
06760 }
06761
06762
06763
06764
06765
06766
06767
06768
06769
06770
06771
06772
06773
06774
06775
06776 static void adsi_goodbye(struct ast_channel *chan)
06777 {
06778 unsigned char buf[256];
06779 int bytes = 0;
06780
06781 if (!ast_adsi_available(chan))
06782 return;
06783 bytes += adsi_logo(buf + bytes);
06784 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06785 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06786 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06787 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06788
06789 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06790 }
06791
06792
06793
06794
06795
06796 static int get_folder(struct ast_channel *chan, int start)
06797 {
06798 int x;
06799 int d;
06800 char fn[PATH_MAX];
06801 d = ast_play_and_wait(chan, "vm-press");
06802 if (d)
06803 return d;
06804 for (x = start; x < 5; x++) {
06805 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06806 return d;
06807 d = ast_play_and_wait(chan, "vm-for");
06808 if (d)
06809 return d;
06810 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06811
06812
06813
06814
06815 if (x == 0) {
06816 if (ast_fileexists(fn, NULL, NULL)) {
06817 d = vm_play_folder_name(chan, fn);
06818 } else {
06819 ast_verb(1, "failed to find %s\n", fn);
06820 d = vm_play_folder_name(chan, "vm-INBOX");
06821 }
06822 } else {
06823 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06824 d = vm_play_folder_name(chan, fn);
06825 }
06826
06827 if (d)
06828 return d;
06829 d = ast_waitfordigit(chan, 500);
06830 if (d)
06831 return d;
06832 }
06833
06834 d = ast_play_and_wait(chan, "vm-tocancel");
06835 if (d)
06836 return d;
06837 d = ast_waitfordigit(chan, 4000);
06838 return d;
06839 }
06840
06841
06842
06843
06844
06845
06846
06847
06848
06849
06850
06851
06852
06853 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06854 {
06855 int res = 0;
06856 int loops = 0;
06857
06858 res = ast_play_and_wait(chan, fn);
06859 while (((res < '0') || (res > '9')) &&
06860 (res != '#') && (res >= 0) &&
06861 loops < 4) {
06862 res = get_folder(chan, 0);
06863 loops++;
06864 }
06865 if (loops == 4) {
06866 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06867 return '#';
06868 }
06869 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06870 return res;
06871 }
06872
06873
06874
06875
06876
06877
06878
06879
06880
06881
06882
06883
06884
06885
06886
06887
06888
06889
06890
06891 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06892 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06893 {
06894 int cmd = 0;
06895 int retries = 0, prepend_duration = 0, already_recorded = 0;
06896 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06897 char textfile[PATH_MAX];
06898 struct ast_config *msg_cfg;
06899 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06900 #ifndef IMAP_STORAGE
06901 signed char zero_gain = 0;
06902 #endif
06903 const char *duration_str;
06904
06905
06906 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06907 strcpy(textfile, msgfile);
06908 strcpy(backup, msgfile);
06909 strcpy(backup_textfile, msgfile);
06910 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06911 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06912 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06913
06914 if ((msg_cfg = ast_config_load(textfile, config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06915 *duration = atoi(duration_str);
06916 } else {
06917 *duration = 0;
06918 }
06919
06920 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06921 if (cmd)
06922 retries = 0;
06923 switch (cmd) {
06924 case '1':
06925
06926 #ifdef IMAP_STORAGE
06927
06928 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06929 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06930 ast_play_and_wait(chan, INTRO);
06931 ast_play_and_wait(chan, "beep");
06932 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06933 if (cmd == -1) {
06934 break;
06935 }
06936 cmd = 't';
06937 #else
06938
06939
06940
06941 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06942 strcpy(textfile, msgfile);
06943 strncat(textfile, ".txt", sizeof(textfile) - 1);
06944 *duration = 0;
06945
06946
06947 if (!valid_config(msg_cfg)) {
06948 cmd = 0;
06949 break;
06950 }
06951
06952
06953 #ifndef IMAP_STORAGE
06954 if (already_recorded) {
06955 ast_filecopy(backup, msgfile, NULL);
06956 copy(backup_textfile, textfile);
06957 }
06958 else {
06959 ast_filecopy(msgfile, backup, NULL);
06960 copy(textfile, backup_textfile);
06961 }
06962 #endif
06963 already_recorded = 1;
06964
06965 if (record_gain)
06966 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06967
06968 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06969
06970 if (cmd == 'S') {
06971 ast_stream_and_wait(chan, vm_pls_try_again, "");
06972 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06973 ast_filerename(backup, msgfile, NULL);
06974 }
06975
06976 if (record_gain)
06977 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06978
06979
06980 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06981 *duration = atoi(duration_str);
06982
06983 if (prepend_duration) {
06984 struct ast_category *msg_cat;
06985
06986 char duration_buf[12];
06987
06988 *duration += prepend_duration;
06989 msg_cat = ast_category_get(msg_cfg, "message");
06990 snprintf(duration_buf, 11, "%ld", *duration);
06991 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06992 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06993 }
06994 }
06995
06996 #endif
06997 break;
06998 case '2':
06999
07000 #ifdef IMAP_STORAGE
07001 *vms->introfn = '\0';
07002 #endif
07003 cmd = 't';
07004 break;
07005 case '*':
07006 cmd = '*';
07007 break;
07008 default:
07009
07010 already_recorded = 0;
07011
07012 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
07013
07014 if (!cmd) {
07015 cmd = ast_play_and_wait(chan, "vm-starmain");
07016
07017 }
07018 if (!cmd) {
07019 cmd = ast_waitfordigit(chan, 6000);
07020 }
07021 if (!cmd) {
07022 retries++;
07023 }
07024 if (retries > 3) {
07025 cmd = '*';
07026 }
07027 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07028 }
07029 }
07030
07031 if (valid_config(msg_cfg))
07032 ast_config_destroy(msg_cfg);
07033 if (prepend_duration)
07034 *duration = prepend_duration;
07035
07036 if (already_recorded && cmd == -1) {
07037
07038 ast_filerename(backup, msgfile, NULL);
07039 rename(backup_textfile, textfile);
07040 }
07041
07042 if (cmd == 't' || cmd == 'S')
07043 cmd = 0;
07044 return cmd;
07045 }
07046
07047 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07048 {
07049 struct ast_event *event;
07050 char *mailbox, *context;
07051
07052
07053 context = mailbox = ast_strdupa(box);
07054 strsep(&context, "@");
07055 if (ast_strlen_zero(context))
07056 context = "default";
07057
07058 if (!(event = ast_event_new(AST_EVENT_MWI,
07059 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07060 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07061 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07062 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07063 AST_EVENT_IE_END))) {
07064 return;
07065 }
07066
07067 ast_event_queue_and_cache(event);
07068 }
07069
07070
07071
07072
07073
07074
07075
07076
07077
07078
07079
07080
07081
07082
07083
07084 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)
07085 {
07086 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07087 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07088 const char *category;
07089 char *myserveremail = serveremail;
07090
07091 ast_channel_lock(chan);
07092 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07093 category = ast_strdupa(category);
07094 }
07095 ast_channel_unlock(chan);
07096
07097 #ifndef IMAP_STORAGE
07098 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07099 #else
07100 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07101 #endif
07102 make_file(fn, sizeof(fn), todir, msgnum);
07103 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07104
07105 if (!ast_strlen_zero(vmu->attachfmt)) {
07106 if (strstr(fmt, vmu->attachfmt))
07107 fmt = vmu->attachfmt;
07108 else
07109 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);
07110 }
07111
07112
07113 fmt = ast_strdupa(fmt);
07114 stringp = fmt;
07115 strsep(&stringp, "|");
07116
07117 if (!ast_strlen_zero(vmu->serveremail))
07118 myserveremail = vmu->serveremail;
07119
07120 if (!ast_strlen_zero(vmu->email)) {
07121 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07122
07123 if (attach_user_voicemail)
07124 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07125
07126
07127 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07128
07129 if (attach_user_voicemail)
07130 DISPOSE(todir, msgnum);
07131 }
07132
07133 if (!ast_strlen_zero(vmu->pager)) {
07134 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07135 }
07136
07137 if (ast_test_flag(vmu, VM_DELETE))
07138 DELETE(todir, msgnum, fn, vmu);
07139
07140
07141 if (ast_app_has_voicemail(ext_context, NULL))
07142 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07143
07144 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07145
07146 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);
07147 run_externnotify(vmu->context, vmu->mailbox, flag);
07148
07149 #ifdef IMAP_STORAGE
07150 vm_delete(fn);
07151 if (ast_test_flag(vmu, VM_DELETE)) {
07152 vm_imap_delete(NULL, vms->curmsg, vmu);
07153 vms->newmessages--;
07154 }
07155 #endif
07156
07157 return 0;
07158 }
07159
07160
07161
07162
07163
07164
07165
07166
07167
07168
07169
07170
07171
07172
07173
07174
07175
07176
07177
07178
07179
07180
07181
07182
07183
07184
07185
07186
07187 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)
07188 {
07189 #ifdef IMAP_STORAGE
07190 int todircount = 0;
07191 struct vm_state *dstvms;
07192 #endif
07193 char username[70]="";
07194 char fn[PATH_MAX];
07195 char ecodes[16] = "#";
07196 int res = 0, cmd = 0;
07197 struct ast_vm_user *receiver = NULL, *vmtmp;
07198 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07199 char *stringp;
07200 const char *s;
07201 int saved_messages = 0;
07202 int valid_extensions = 0;
07203 char *dir;
07204 int curmsg;
07205 char urgent_str[7] = "";
07206 int prompt_played = 0;
07207 #ifndef IMAP_STORAGE
07208 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07209 #endif
07210 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07211 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07212 }
07213
07214 if (vms == NULL) return -1;
07215 dir = vms->curdir;
07216 curmsg = vms->curmsg;
07217
07218 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07219 while (!res && !valid_extensions) {
07220 int use_directory = 0;
07221 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07222 int done = 0;
07223 int retries = 0;
07224 cmd = 0;
07225 while ((cmd >= 0) && !done ){
07226 if (cmd)
07227 retries = 0;
07228 switch (cmd) {
07229 case '1':
07230 use_directory = 0;
07231 done = 1;
07232 break;
07233 case '2':
07234 use_directory = 1;
07235 done = 1;
07236 break;
07237 case '*':
07238 cmd = 't';
07239 done = 1;
07240 break;
07241 default:
07242
07243 cmd = ast_play_and_wait(chan, "vm-forward");
07244 if (!cmd) {
07245 cmd = ast_waitfordigit(chan, 3000);
07246 }
07247 if (!cmd) {
07248 retries++;
07249 }
07250 if (retries > 3) {
07251 cmd = 't';
07252 done = 1;
07253 }
07254 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07255 }
07256 }
07257 if (cmd < 0 || cmd == 't')
07258 break;
07259 }
07260
07261 if (use_directory) {
07262
07263
07264 char old_context[sizeof(chan->context)];
07265 char old_exten[sizeof(chan->exten)];
07266 int old_priority;
07267 struct ast_app* directory_app;
07268
07269 directory_app = pbx_findapp("Directory");
07270 if (directory_app) {
07271 char vmcontext[256];
07272
07273 memcpy(old_context, chan->context, sizeof(chan->context));
07274 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07275 old_priority = chan->priority;
07276
07277
07278 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07279 res = pbx_exec(chan, directory_app, vmcontext);
07280
07281 ast_copy_string(username, chan->exten, sizeof(username));
07282
07283
07284 memcpy(chan->context, old_context, sizeof(chan->context));
07285 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07286 chan->priority = old_priority;
07287 } else {
07288 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07289 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07290 }
07291 } else {
07292
07293 res = ast_streamfile(chan, "vm-extension", chan->language);
07294 prompt_played++;
07295 if (res || prompt_played > 4)
07296 break;
07297 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07298 break;
07299 }
07300
07301
07302 if (ast_strlen_zero(username))
07303 continue;
07304 stringp = username;
07305 s = strsep(&stringp, "*");
07306
07307 valid_extensions = 1;
07308 while (s) {
07309 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07310 int oldmsgs;
07311 int newmsgs;
07312 int capacity;
07313 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07314 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07315
07316 res = ast_play_and_wait(chan, "pbx-invalid");
07317 valid_extensions = 0;
07318 break;
07319 }
07320 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07321 if ((newmsgs + oldmsgs) >= capacity) {
07322 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07323 res = ast_play_and_wait(chan, "vm-mailboxfull");
07324 valid_extensions = 0;
07325 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07326 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07327 free_user(vmtmp);
07328 }
07329 inprocess_count(receiver->mailbox, receiver->context, -1);
07330 break;
07331 }
07332 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07333 } else {
07334
07335
07336
07337
07338
07339 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07340 free_user(receiver);
07341 }
07342 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07343
07344 res = ast_play_and_wait(chan, "pbx-invalid");
07345 valid_extensions = 0;
07346 break;
07347 }
07348
07349
07350 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07351 RETRIEVE(fn, -1, s, receiver->context);
07352 if (ast_fileexists(fn, NULL, NULL) > 0) {
07353 res = ast_stream_and_wait(chan, fn, ecodes);
07354 if (res) {
07355 DISPOSE(fn, -1);
07356 return res;
07357 }
07358 } else {
07359 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07360 }
07361 DISPOSE(fn, -1);
07362
07363 s = strsep(&stringp, "*");
07364 }
07365
07366 if (valid_extensions)
07367 break;
07368 }
07369
07370 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07371 return res;
07372 if (is_new_message == 1) {
07373 struct leave_vm_options leave_options;
07374 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07375 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07376
07377
07378 memset(&leave_options, 0, sizeof(leave_options));
07379 leave_options.record_gain = record_gain;
07380 cmd = leave_voicemail(chan, mailbox, &leave_options);
07381 } else {
07382
07383 long duration = 0;
07384 struct vm_state vmstmp;
07385 int copy_msg_result = 0;
07386 memcpy(&vmstmp, vms, sizeof(vmstmp));
07387
07388 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07389
07390 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07391 if (!cmd) {
07392 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07393 #ifdef IMAP_STORAGE
07394 int attach_user_voicemail;
07395 char *myserveremail = serveremail;
07396
07397
07398 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07399 if (!dstvms) {
07400 dstvms = create_vm_state_from_user(vmtmp);
07401 }
07402 if (dstvms) {
07403 init_mailstream(dstvms, 0);
07404 if (!dstvms->mailstream) {
07405 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07406 } else {
07407 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07408 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07409 }
07410 } else {
07411 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07412 }
07413 if (!ast_strlen_zero(vmtmp->serveremail))
07414 myserveremail = vmtmp->serveremail;
07415 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07416
07417 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07418 dstvms->curbox,
07419 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07420 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07421 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07422 NULL, urgent_str);
07423 #else
07424 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07425 #endif
07426 saved_messages++;
07427 AST_LIST_REMOVE_CURRENT(list);
07428 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07429 free_user(vmtmp);
07430 if (res)
07431 break;
07432 }
07433 AST_LIST_TRAVERSE_SAFE_END;
07434 if (saved_messages > 0 && !copy_msg_result) {
07435
07436
07437
07438
07439
07440
07441
07442
07443 #ifdef IMAP_STORAGE
07444
07445 if (ast_strlen_zero(vmstmp.introfn))
07446 #endif
07447 res = ast_play_and_wait(chan, "vm-msgsaved");
07448 }
07449 #ifndef IMAP_STORAGE
07450 else {
07451
07452 res = ast_play_and_wait(chan, "vm-mailboxfull");
07453 }
07454
07455 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07456 strcpy(textfile, msgfile);
07457 strcpy(backup, msgfile);
07458 strcpy(backup_textfile, msgfile);
07459 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07460 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07461 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07462 if (ast_fileexists(backup, NULL, NULL) > 0) {
07463 ast_filerename(backup, msgfile, NULL);
07464 rename(backup_textfile, textfile);
07465 }
07466 #endif
07467 }
07468 DISPOSE(dir, curmsg);
07469 #ifndef IMAP_STORAGE
07470 if (cmd) {
07471 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07472 strcpy(textfile, msgfile);
07473 strcpy(backup_textfile, msgfile);
07474 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07475 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07476 rename(backup_textfile, textfile);
07477 }
07478 #endif
07479 }
07480
07481
07482 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07483 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07484 free_user(vmtmp);
07485 }
07486 return res ? res : cmd;
07487 }
07488
07489 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07490 {
07491 int res;
07492 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07493 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07494 return res;
07495 }
07496
07497 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07498 {
07499 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07500 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);
07501 }
07502
07503 static int play_message_category(struct ast_channel *chan, const char *category)
07504 {
07505 int res = 0;
07506
07507 if (!ast_strlen_zero(category))
07508 res = ast_play_and_wait(chan, category);
07509
07510 if (res) {
07511 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07512 res = 0;
07513 }
07514
07515 return res;
07516 }
07517
07518 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07519 {
07520 int res = 0;
07521 struct vm_zone *the_zone = NULL;
07522 time_t t;
07523
07524 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07525 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07526 return 0;
07527 }
07528
07529
07530 if (!ast_strlen_zero(vmu->zonetag)) {
07531
07532 struct vm_zone *z;
07533 AST_LIST_LOCK(&zones);
07534 AST_LIST_TRAVERSE(&zones, z, list) {
07535 if (!strcmp(z->name, vmu->zonetag)) {
07536 the_zone = z;
07537 break;
07538 }
07539 }
07540 AST_LIST_UNLOCK(&zones);
07541 }
07542
07543
07544 #if 0
07545
07546 ast_localtime(&t, &time_now, NULL);
07547 tv_now = ast_tvnow();
07548 ast_localtime(&tv_now, &time_then, NULL);
07549
07550
07551 if (time_now.tm_year == time_then.tm_year)
07552 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07553 else
07554 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07555 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07556
07557
07558 #endif
07559 if (the_zone) {
07560 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07561 } else if (!strncasecmp(chan->language, "de", 2)) {
07562 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07563 } else if (!strncasecmp(chan->language, "gr", 2)) {
07564 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07565 } else if (!strncasecmp(chan->language, "it", 2)) {
07566 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);
07567 } else if (!strncasecmp(chan->language, "nl", 2)) {
07568 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07569 } else if (!strncasecmp(chan->language, "no", 2)) {
07570 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07571 } else if (!strncasecmp(chan->language, "pl", 2)) {
07572 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07573 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07574 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);
07575 } else if (!strncasecmp(chan->language, "se", 2)) {
07576 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07577 } else if (!strncasecmp(chan->language, "zh", 2)) {
07578 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07579 } else if (!strncasecmp(chan->language, "vi", 2)) {
07580 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);
07581 } else {
07582 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07583 }
07584 #if 0
07585 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07586 #endif
07587 return res;
07588 }
07589
07590
07591
07592 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07593 {
07594 int res = 0;
07595 int i;
07596 char *callerid, *name;
07597 char prefile[PATH_MAX] = "";
07598
07599
07600
07601
07602
07603
07604
07605
07606
07607 if ((cid == NULL)||(context == NULL))
07608 return res;
07609
07610
07611 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07612 ast_callerid_parse(cid, &name, &callerid);
07613 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07614
07615
07616 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07617 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07618 if ((strcmp(cidinternalcontexts[i], context) == 0))
07619 break;
07620 }
07621 if (i != MAX_NUM_CID_CONTEXTS){
07622 if (!res) {
07623 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07624 if (!ast_strlen_zero(prefile)) {
07625
07626 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07627 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07628 if (!callback)
07629 res = wait_file2(chan, vms, "vm-from");
07630 res = ast_stream_and_wait(chan, prefile, "");
07631 } else {
07632 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07633
07634 if (!callback)
07635 res = wait_file2(chan, vms, "vm-from-extension");
07636 res = ast_say_digit_str(chan, callerid, "", chan->language);
07637 }
07638 }
07639 }
07640 } else if (!res) {
07641 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07642
07643 if (!callback)
07644 res = wait_file2(chan, vms, "vm-from-phonenumber");
07645 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07646 }
07647 } else {
07648
07649 ast_debug(1, "VM-CID: From an unknown number\n");
07650
07651 res = wait_file2(chan, vms, "vm-unknown-caller");
07652 }
07653 return res;
07654 }
07655
07656 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07657 {
07658 int res = 0;
07659 int durationm;
07660 int durations;
07661
07662 if (duration == NULL)
07663 return res;
07664
07665
07666 durations = atoi(duration);
07667 durationm = (durations / 60);
07668
07669 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07670
07671 if ((!res) && (durationm >= minduration)) {
07672 res = wait_file2(chan, vms, "vm-duration");
07673
07674
07675 if (!strncasecmp(chan->language, "pl", 2)) {
07676 div_t num = div(durationm, 10);
07677
07678 if (durationm == 1) {
07679 res = ast_play_and_wait(chan, "digits/1z");
07680 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07681 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07682 if (num.rem == 2) {
07683 if (!num.quot) {
07684 res = ast_play_and_wait(chan, "digits/2-ie");
07685 } else {
07686 res = say_and_wait(chan, durationm - 2 , chan->language);
07687 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07688 }
07689 } else {
07690 res = say_and_wait(chan, durationm, chan->language);
07691 }
07692 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07693 } else {
07694 res = say_and_wait(chan, durationm, chan->language);
07695 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07696 }
07697
07698 } else {
07699 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07700 res = wait_file2(chan, vms, "vm-minutes");
07701 }
07702 }
07703 return res;
07704 }
07705
07706 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07707 {
07708 int res = 0;
07709 char filename[256], *cid;
07710 const char *origtime, *context, *category, *duration, *flag;
07711 struct ast_config *msg_cfg;
07712 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07713
07714 vms->starting = 0;
07715 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07716 adsi_message(chan, vms);
07717 if (!vms->curmsg) {
07718 res = wait_file2(chan, vms, "vm-first");
07719 } else if (vms->curmsg == vms->lastmsg) {
07720 res = wait_file2(chan, vms, "vm-last");
07721 }
07722
07723 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07724 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07725 msg_cfg = ast_config_load(filename, config_flags);
07726 if (!valid_config(msg_cfg)) {
07727 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07728 return 0;
07729 }
07730 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07731
07732
07733 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07734 res = wait_file2(chan, vms, "vm-Urgent");
07735 }
07736
07737 if (!res) {
07738
07739
07740 if (!strncasecmp(chan->language, "pl", 2)) {
07741 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07742 int ten, one;
07743 char nextmsg[256];
07744 ten = (vms->curmsg + 1) / 10;
07745 one = (vms->curmsg + 1) % 10;
07746
07747 if (vms->curmsg < 20) {
07748 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07749 res = wait_file2(chan, vms, nextmsg);
07750 } else {
07751 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07752 res = wait_file2(chan, vms, nextmsg);
07753 if (one > 0) {
07754 if (!res) {
07755 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07756 res = wait_file2(chan, vms, nextmsg);
07757 }
07758 }
07759 }
07760 }
07761 if (!res)
07762 res = wait_file2(chan, vms, "vm-message");
07763
07764 } else if (!strncasecmp(chan->language, "he", 2)) {
07765 if (!vms->curmsg) {
07766 res = wait_file2(chan, vms, "vm-message");
07767 res = wait_file2(chan, vms, "vm-first");
07768 } else if (vms->curmsg == vms->lastmsg) {
07769 res = wait_file2(chan, vms, "vm-message");
07770 res = wait_file2(chan, vms, "vm-last");
07771 } else {
07772 res = wait_file2(chan, vms, "vm-message");
07773 res = wait_file2(chan, vms, "vm-number");
07774 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07775 }
07776
07777 } else if (!strncasecmp(chan->language, "vi", 2)) {
07778 if (!vms->curmsg) {
07779 res = wait_file2(chan, vms, "vm-message");
07780 res = wait_file2(chan, vms, "vm-first");
07781 } else if (vms->curmsg == vms->lastmsg) {
07782 res = wait_file2(chan, vms, "vm-message");
07783 res = wait_file2(chan, vms, "vm-last");
07784 } else {
07785 res = wait_file2(chan, vms, "vm-message");
07786 res = wait_file2(chan, vms, "vm-number");
07787 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07788 }
07789 } else {
07790 if (!strncasecmp(chan->language, "se", 2)) {
07791 res = wait_file2(chan, vms, "vm-meddelandet");
07792 } else {
07793 res = wait_file2(chan, vms, "vm-message");
07794 }
07795 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07796 if (!res) {
07797 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07798 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07799 }
07800 }
07801 }
07802 }
07803
07804 if (!valid_config(msg_cfg)) {
07805 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07806 return 0;
07807 }
07808
07809 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07810 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07811 DISPOSE(vms->curdir, vms->curmsg);
07812 ast_config_destroy(msg_cfg);
07813 return 0;
07814 }
07815
07816 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07817 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07818 category = ast_variable_retrieve(msg_cfg, "message", "category");
07819
07820 context = ast_variable_retrieve(msg_cfg, "message", "context");
07821 if (!strncasecmp("macro", context, 5))
07822 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07823 if (!res) {
07824 res = play_message_category(chan, category);
07825 }
07826 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07827 res = play_message_datetime(chan, vmu, origtime, filename);
07828 }
07829 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07830 res = play_message_callerid(chan, vms, cid, context, 0);
07831 }
07832 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07833 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07834 }
07835
07836 if (res == '1') {
07837 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07838 res = 0;
07839 }
07840 ast_config_destroy(msg_cfg);
07841
07842 if (!res) {
07843 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07844 #ifdef IMAP_STORAGE
07845 ast_mutex_lock(&vms->lock);
07846 #endif
07847 vms->heard[vms->curmsg] = 1;
07848 #ifdef IMAP_STORAGE
07849 ast_mutex_unlock(&vms->lock);
07850
07851
07852
07853 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07854 wait_file(chan, vms, vms->introfn);
07855 }
07856 #endif
07857 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07858 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07859 res = 0;
07860 }
07861 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07862 }
07863 DISPOSE(vms->curdir, vms->curmsg);
07864 return res;
07865 }
07866
07867 #ifdef IMAP_STORAGE
07868 static int imap_remove_file(char *dir, int msgnum)
07869 {
07870 char fn[PATH_MAX];
07871 char full_fn[PATH_MAX];
07872 char intro[PATH_MAX] = {0,};
07873
07874 if (msgnum > -1) {
07875 make_file(fn, sizeof(fn), dir, msgnum);
07876 snprintf(intro, sizeof(intro), "%sintro", fn);
07877 } else
07878 ast_copy_string(fn, dir, sizeof(fn));
07879
07880 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07881 ast_filedelete(fn, NULL);
07882 if (!ast_strlen_zero(intro)) {
07883 ast_filedelete(intro, NULL);
07884 }
07885 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07886 unlink(full_fn);
07887 }
07888 return 0;
07889 }
07890
07891
07892
07893 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07894 {
07895 char *file, *filename;
07896 char *attachment;
07897 char arg[10];
07898 int i;
07899 BODY* body;
07900
07901 file = strrchr(ast_strdupa(dir), '/');
07902 if (file) {
07903 *file++ = '\0';
07904 } else {
07905 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07906 return -1;
07907 }
07908
07909 ast_mutex_lock(&vms->lock);
07910 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07911 mail_fetchstructure(vms->mailstream, i + 1, &body);
07912
07913 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07914 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07915 } else {
07916 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07917 ast_mutex_unlock(&vms->lock);
07918 return -1;
07919 }
07920 filename = strsep(&attachment, ".");
07921 if (!strcmp(filename, file)) {
07922 sprintf(arg, "%d", i + 1);
07923 mail_setflag(vms->mailstream, arg, "\\DELETED");
07924 }
07925 }
07926 mail_expunge(vms->mailstream);
07927 ast_mutex_unlock(&vms->lock);
07928 return 0;
07929 }
07930
07931 #elif !defined(IMAP_STORAGE)
07932 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07933 {
07934 int count_msg, last_msg;
07935
07936 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07937
07938
07939
07940
07941 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07942
07943
07944 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07945
07946
07947 count_msg = count_messages(vmu, vms->curdir);
07948 if (count_msg < 0) {
07949 return count_msg;
07950 } else {
07951 vms->lastmsg = count_msg - 1;
07952 }
07953
07954 if (vm_allocate_dh(vms, vmu, count_msg)) {
07955 return -1;
07956 }
07957
07958
07959
07960
07961
07962
07963
07964
07965 if (vm_lock_path(vms->curdir)) {
07966 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07967 return ERROR_LOCK_PATH;
07968 }
07969
07970
07971 last_msg = last_message_index(vmu, vms->curdir);
07972 ast_unlock_path(vms->curdir);
07973
07974 if (last_msg < -1) {
07975 return last_msg;
07976 } else if (vms->lastmsg != last_msg) {
07977 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);
07978 resequence_mailbox(vmu, vms->curdir, count_msg);
07979 }
07980
07981 return 0;
07982 }
07983 #endif
07984
07985 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07986 {
07987 int x = 0;
07988 int last_msg_idx = 0;
07989
07990 #ifndef IMAP_STORAGE
07991 int res = 0, nummsg;
07992 char fn2[PATH_MAX];
07993 #endif
07994
07995 if (vms->lastmsg <= -1) {
07996 goto done;
07997 }
07998
07999 vms->curmsg = -1;
08000 #ifndef IMAP_STORAGE
08001
08002 if (vm_lock_path(vms->curdir)) {
08003 return ERROR_LOCK_PATH;
08004 }
08005
08006
08007 last_msg_idx = last_message_index(vmu, vms->curdir);
08008 if (last_msg_idx != vms->lastmsg) {
08009 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
08010 }
08011
08012
08013 for (x = 0; x < last_msg_idx + 1; x++) {
08014 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
08015
08016 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08017 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
08018 break;
08019 }
08020 vms->curmsg++;
08021 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08022 if (strcmp(vms->fn, fn2)) {
08023 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08024 }
08025 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08026
08027 res = save_to_folder(vmu, vms, x, 1);
08028 if (res == ERROR_LOCK_PATH) {
08029
08030 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08031 vms->deleted[x] = 0;
08032 vms->heard[x] = 0;
08033 --x;
08034 }
08035 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08036
08037 res = save_to_folder(vmu, vms, x, 10);
08038 if (res == ERROR_LOCK_PATH) {
08039
08040 vms->deleted[x] = 0;
08041 vms->heard[x] = 0;
08042 --x;
08043 }
08044 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08045
08046
08047 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08048 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08049 DELETE(vms->curdir, x, vms->fn, vmu);
08050 }
08051 }
08052 }
08053
08054
08055 nummsg = x - 1;
08056 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08057 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08058 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08059 DELETE(vms->curdir, x, vms->fn, vmu);
08060 }
08061 }
08062 ast_unlock_path(vms->curdir);
08063 #else
08064 ast_mutex_lock(&vms->lock);
08065 if (vms->deleted) {
08066
08067
08068 last_msg_idx = vms->dh_arraysize;
08069 for (x = last_msg_idx - 1; x >= 0; x--) {
08070 if (vms->deleted[x]) {
08071 ast_debug(3, "IMAP delete of %d\n", x);
08072 DELETE(vms->curdir, x, vms->fn, vmu);
08073 }
08074 }
08075 }
08076 #endif
08077
08078 done:
08079 if (vms->deleted) {
08080 ast_free(vms->deleted);
08081 vms->deleted = NULL;
08082 }
08083 if (vms->heard) {
08084 ast_free(vms->heard);
08085 vms->heard = NULL;
08086 }
08087 vms->dh_arraysize = 0;
08088 #ifdef IMAP_STORAGE
08089 ast_mutex_unlock(&vms->lock);
08090 #endif
08091
08092 return 0;
08093 }
08094
08095
08096
08097
08098
08099
08100
08101 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08102 {
08103 int cmd;
08104 char *buf;
08105
08106 buf = ast_alloca(strlen(box) + 2);
08107 strcpy(buf, box);
08108 strcat(buf, "s");
08109
08110 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08111 cmd = ast_play_and_wait(chan, buf);
08112 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08113 } else {
08114 cmd = ast_play_and_wait(chan, "vm-messages");
08115 return cmd ? cmd : ast_play_and_wait(chan, box);
08116 }
08117 }
08118
08119 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08120 {
08121 int cmd;
08122
08123 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08124 if (!strcasecmp(box, "vm-INBOX"))
08125 cmd = ast_play_and_wait(chan, "vm-new-e");
08126 else
08127 cmd = ast_play_and_wait(chan, "vm-old-e");
08128 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08129 } else {
08130 cmd = ast_play_and_wait(chan, "vm-messages");
08131 return cmd ? cmd : ast_play_and_wait(chan, box);
08132 }
08133 }
08134
08135 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08136 {
08137 int cmd;
08138
08139 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08140 cmd = ast_play_and_wait(chan, "vm-messages");
08141 return cmd ? cmd : ast_play_and_wait(chan, box);
08142 } else {
08143 cmd = ast_play_and_wait(chan, box);
08144 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08145 }
08146 }
08147
08148 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08149 {
08150 int cmd;
08151
08152 if ( !strncasecmp(chan->language, "it", 2) ||
08153 !strncasecmp(chan->language, "es", 2) ||
08154 !strncasecmp(chan->language, "pt", 2)) {
08155 cmd = ast_play_and_wait(chan, "vm-messages");
08156 return cmd ? cmd : ast_play_and_wait(chan, box);
08157 } else if (!strncasecmp(chan->language, "gr", 2)) {
08158 return vm_play_folder_name_gr(chan, box);
08159 } else if (!strncasecmp(chan->language, "he", 2)) {
08160 return ast_play_and_wait(chan, box);
08161 } else if (!strncasecmp(chan->language, "pl", 2)) {
08162 return vm_play_folder_name_pl(chan, box);
08163 } else if (!strncasecmp(chan->language, "ua", 2)) {
08164 return vm_play_folder_name_ua(chan, box);
08165 } else if (!strncasecmp(chan->language, "vi", 2)) {
08166 return ast_play_and_wait(chan, box);
08167 } else {
08168 cmd = ast_play_and_wait(chan, box);
08169 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08170 }
08171 }
08172
08173
08174
08175
08176
08177
08178
08179
08180
08181
08182
08183
08184
08185 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08186 {
08187 int res = 0;
08188
08189 if (vms->newmessages) {
08190 res = ast_play_and_wait(chan, "vm-youhave");
08191 if (!res)
08192 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08193 if (!res) {
08194 if ((vms->newmessages == 1)) {
08195 res = ast_play_and_wait(chan, "vm-INBOX");
08196 if (!res)
08197 res = ast_play_and_wait(chan, "vm-message");
08198 } else {
08199 res = ast_play_and_wait(chan, "vm-INBOXs");
08200 if (!res)
08201 res = ast_play_and_wait(chan, "vm-messages");
08202 }
08203 }
08204 } else if (vms->oldmessages){
08205 res = ast_play_and_wait(chan, "vm-youhave");
08206 if (!res)
08207 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08208 if ((vms->oldmessages == 1)){
08209 res = ast_play_and_wait(chan, "vm-Old");
08210 if (!res)
08211 res = ast_play_and_wait(chan, "vm-message");
08212 } else {
08213 res = ast_play_and_wait(chan, "vm-Olds");
08214 if (!res)
08215 res = ast_play_and_wait(chan, "vm-messages");
08216 }
08217 } else if (!vms->oldmessages && !vms->newmessages)
08218 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08219 return res;
08220 }
08221
08222
08223
08224
08225
08226
08227
08228
08229
08230
08231
08232
08233
08234
08235
08236
08237
08238
08239
08240
08241
08242
08243
08244
08245
08246
08247
08248
08249
08250
08251
08252
08253
08254
08255
08256
08257
08258
08259
08260
08261
08262
08263
08264
08265
08266
08267
08268
08269
08270
08271
08272
08273
08274
08275
08276
08277
08278
08279 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08280 {
08281 int res;
08282 int lastnum = 0;
08283
08284 res = ast_play_and_wait(chan, "vm-youhave");
08285
08286 if (!res && vms->newmessages) {
08287 lastnum = vms->newmessages;
08288
08289 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08290 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08291 }
08292
08293 if (!res && vms->oldmessages) {
08294 res = ast_play_and_wait(chan, "vm-and");
08295 }
08296 }
08297
08298 if (!res && vms->oldmessages) {
08299 lastnum = vms->oldmessages;
08300
08301 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08302 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08303 }
08304 }
08305
08306 if (!res) {
08307 if (lastnum == 0) {
08308 res = ast_play_and_wait(chan, "vm-no");
08309 }
08310 if (!res) {
08311 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08312 }
08313 }
08314
08315 return res;
08316 }
08317
08318
08319 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08320 {
08321 int res = 0;
08322
08323
08324 if (!res) {
08325 if ((vms->newmessages) || (vms->oldmessages)) {
08326 res = ast_play_and_wait(chan, "vm-youhave");
08327 }
08328
08329
08330
08331
08332
08333 if (vms->newmessages) {
08334 if (!res) {
08335 if (vms->newmessages == 1) {
08336 res = ast_play_and_wait(chan, "vm-INBOX1");
08337 } else {
08338 if (vms->newmessages == 2) {
08339 res = ast_play_and_wait(chan, "vm-shtei");
08340 } else {
08341 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08342 }
08343 res = ast_play_and_wait(chan, "vm-INBOX");
08344 }
08345 }
08346 if (vms->oldmessages && !res) {
08347 res = ast_play_and_wait(chan, "vm-and");
08348 if (vms->oldmessages == 1) {
08349 res = ast_play_and_wait(chan, "vm-Old1");
08350 } else {
08351 if (vms->oldmessages == 2) {
08352 res = ast_play_and_wait(chan, "vm-shtei");
08353 } else {
08354 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08355 }
08356 res = ast_play_and_wait(chan, "vm-Old");
08357 }
08358 }
08359 }
08360 if (!res && vms->oldmessages && !vms->newmessages) {
08361 if (!res) {
08362 if (vms->oldmessages == 1) {
08363 res = ast_play_and_wait(chan, "vm-Old1");
08364 } else {
08365 if (vms->oldmessages == 2) {
08366 res = ast_play_and_wait(chan, "vm-shtei");
08367 } else {
08368 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08369 }
08370 res = ast_play_and_wait(chan, "vm-Old");
08371 }
08372 }
08373 }
08374 if (!res) {
08375 if (!vms->oldmessages && !vms->newmessages) {
08376 if (!res) {
08377 res = ast_play_and_wait(chan, "vm-nomessages");
08378 }
08379 }
08380 }
08381 }
08382 return res;
08383 }
08384
08385
08386 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08387 {
08388 int res;
08389
08390
08391 res = ast_play_and_wait(chan, "vm-youhave");
08392 if (!res) {
08393 if (vms->urgentmessages) {
08394 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08395 if (!res)
08396 res = ast_play_and_wait(chan, "vm-Urgent");
08397 if ((vms->oldmessages || vms->newmessages) && !res) {
08398 res = ast_play_and_wait(chan, "vm-and");
08399 } else if (!res) {
08400 if ((vms->urgentmessages == 1))
08401 res = ast_play_and_wait(chan, "vm-message");
08402 else
08403 res = ast_play_and_wait(chan, "vm-messages");
08404 }
08405 }
08406 if (vms->newmessages) {
08407 res = say_and_wait(chan, vms->newmessages, chan->language);
08408 if (!res)
08409 res = ast_play_and_wait(chan, "vm-INBOX");
08410 if (vms->oldmessages && !res)
08411 res = ast_play_and_wait(chan, "vm-and");
08412 else if (!res) {
08413 if ((vms->newmessages == 1))
08414 res = ast_play_and_wait(chan, "vm-message");
08415 else
08416 res = ast_play_and_wait(chan, "vm-messages");
08417 }
08418
08419 }
08420 if (!res && vms->oldmessages) {
08421 res = say_and_wait(chan, vms->oldmessages, chan->language);
08422 if (!res)
08423 res = ast_play_and_wait(chan, "vm-Old");
08424 if (!res) {
08425 if (vms->oldmessages == 1)
08426 res = ast_play_and_wait(chan, "vm-message");
08427 else
08428 res = ast_play_and_wait(chan, "vm-messages");
08429 }
08430 }
08431 if (!res) {
08432 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08433 res = ast_play_and_wait(chan, "vm-no");
08434 if (!res)
08435 res = ast_play_and_wait(chan, "vm-messages");
08436 }
08437 }
08438 }
08439 return res;
08440 }
08441
08442
08443 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08444 {
08445
08446 int res;
08447 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08448 res = ast_play_and_wait(chan, "vm-no") ||
08449 ast_play_and_wait(chan, "vm-message");
08450 else
08451 res = ast_play_and_wait(chan, "vm-youhave");
08452 if (!res && vms->newmessages) {
08453 res = (vms->newmessages == 1) ?
08454 ast_play_and_wait(chan, "digits/un") ||
08455 ast_play_and_wait(chan, "vm-nuovo") ||
08456 ast_play_and_wait(chan, "vm-message") :
08457
08458 say_and_wait(chan, vms->newmessages, chan->language) ||
08459 ast_play_and_wait(chan, "vm-nuovi") ||
08460 ast_play_and_wait(chan, "vm-messages");
08461 if (!res && vms->oldmessages)
08462 res = ast_play_and_wait(chan, "vm-and");
08463 }
08464 if (!res && vms->oldmessages) {
08465 res = (vms->oldmessages == 1) ?
08466 ast_play_and_wait(chan, "digits/un") ||
08467 ast_play_and_wait(chan, "vm-vecchio") ||
08468 ast_play_and_wait(chan, "vm-message") :
08469
08470 say_and_wait(chan, vms->oldmessages, chan->language) ||
08471 ast_play_and_wait(chan, "vm-vecchi") ||
08472 ast_play_and_wait(chan, "vm-messages");
08473 }
08474 return res;
08475 }
08476
08477
08478 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08479 {
08480
08481 int res;
08482 div_t num;
08483
08484 if (!vms->oldmessages && !vms->newmessages) {
08485 res = ast_play_and_wait(chan, "vm-no");
08486 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08487 return res;
08488 } else {
08489 res = ast_play_and_wait(chan, "vm-youhave");
08490 }
08491
08492 if (vms->newmessages) {
08493 num = div(vms->newmessages, 10);
08494 if (vms->newmessages == 1) {
08495 res = ast_play_and_wait(chan, "digits/1-a");
08496 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08497 res = res ? res : ast_play_and_wait(chan, "vm-message");
08498 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08499 if (num.rem == 2) {
08500 if (!num.quot) {
08501 res = ast_play_and_wait(chan, "digits/2-ie");
08502 } else {
08503 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08504 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08505 }
08506 } else {
08507 res = say_and_wait(chan, vms->newmessages, chan->language);
08508 }
08509 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08510 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08511 } else {
08512 res = say_and_wait(chan, vms->newmessages, chan->language);
08513 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08514 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08515 }
08516 if (!res && vms->oldmessages)
08517 res = ast_play_and_wait(chan, "vm-and");
08518 }
08519 if (!res && vms->oldmessages) {
08520 num = div(vms->oldmessages, 10);
08521 if (vms->oldmessages == 1) {
08522 res = ast_play_and_wait(chan, "digits/1-a");
08523 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08524 res = res ? res : ast_play_and_wait(chan, "vm-message");
08525 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08526 if (num.rem == 2) {
08527 if (!num.quot) {
08528 res = ast_play_and_wait(chan, "digits/2-ie");
08529 } else {
08530 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08531 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08532 }
08533 } else {
08534 res = say_and_wait(chan, vms->oldmessages, chan->language);
08535 }
08536 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08537 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08538 } else {
08539 res = say_and_wait(chan, vms->oldmessages, chan->language);
08540 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08541 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08542 }
08543 }
08544
08545 return res;
08546 }
08547
08548
08549 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08550 {
08551
08552 int res;
08553
08554 res = ast_play_and_wait(chan, "vm-youhave");
08555 if (res)
08556 return res;
08557
08558 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08559 res = ast_play_and_wait(chan, "vm-no");
08560 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08561 return res;
08562 }
08563
08564 if (vms->newmessages) {
08565 if ((vms->newmessages == 1)) {
08566 res = ast_play_and_wait(chan, "digits/ett");
08567 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08568 res = res ? res : ast_play_and_wait(chan, "vm-message");
08569 } else {
08570 res = say_and_wait(chan, vms->newmessages, chan->language);
08571 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08572 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08573 }
08574 if (!res && vms->oldmessages)
08575 res = ast_play_and_wait(chan, "vm-and");
08576 }
08577 if (!res && vms->oldmessages) {
08578 if (vms->oldmessages == 1) {
08579 res = ast_play_and_wait(chan, "digits/ett");
08580 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08581 res = res ? res : ast_play_and_wait(chan, "vm-message");
08582 } else {
08583 res = say_and_wait(chan, vms->oldmessages, chan->language);
08584 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08585 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08586 }
08587 }
08588
08589 return res;
08590 }
08591
08592
08593 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08594 {
08595
08596 int res;
08597
08598 res = ast_play_and_wait(chan, "vm-youhave");
08599 if (res)
08600 return res;
08601
08602 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08603 res = ast_play_and_wait(chan, "vm-no");
08604 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08605 return res;
08606 }
08607
08608 if (vms->newmessages) {
08609 if ((vms->newmessages == 1)) {
08610 res = ast_play_and_wait(chan, "digits/1");
08611 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08612 res = res ? res : ast_play_and_wait(chan, "vm-message");
08613 } else {
08614 res = say_and_wait(chan, vms->newmessages, chan->language);
08615 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08616 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08617 }
08618 if (!res && vms->oldmessages)
08619 res = ast_play_and_wait(chan, "vm-and");
08620 }
08621 if (!res && vms->oldmessages) {
08622 if (vms->oldmessages == 1) {
08623 res = ast_play_and_wait(chan, "digits/1");
08624 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08625 res = res ? res : ast_play_and_wait(chan, "vm-message");
08626 } else {
08627 res = say_and_wait(chan, vms->oldmessages, chan->language);
08628 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08629 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08630 }
08631 }
08632
08633 return res;
08634 }
08635
08636
08637 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08638 {
08639
08640 int res;
08641 res = ast_play_and_wait(chan, "vm-youhave");
08642 if (!res) {
08643 if (vms->newmessages) {
08644 if ((vms->newmessages == 1))
08645 res = ast_play_and_wait(chan, "digits/1F");
08646 else
08647 res = say_and_wait(chan, vms->newmessages, chan->language);
08648 if (!res)
08649 res = ast_play_and_wait(chan, "vm-INBOX");
08650 if (vms->oldmessages && !res)
08651 res = ast_play_and_wait(chan, "vm-and");
08652 else if (!res) {
08653 if ((vms->newmessages == 1))
08654 res = ast_play_and_wait(chan, "vm-message");
08655 else
08656 res = ast_play_and_wait(chan, "vm-messages");
08657 }
08658
08659 }
08660 if (!res && vms->oldmessages) {
08661 if (vms->oldmessages == 1)
08662 res = ast_play_and_wait(chan, "digits/1F");
08663 else
08664 res = say_and_wait(chan, vms->oldmessages, chan->language);
08665 if (!res)
08666 res = ast_play_and_wait(chan, "vm-Old");
08667 if (!res) {
08668 if (vms->oldmessages == 1)
08669 res = ast_play_and_wait(chan, "vm-message");
08670 else
08671 res = ast_play_and_wait(chan, "vm-messages");
08672 }
08673 }
08674 if (!res) {
08675 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08676 res = ast_play_and_wait(chan, "vm-no");
08677 if (!res)
08678 res = ast_play_and_wait(chan, "vm-messages");
08679 }
08680 }
08681 }
08682 return res;
08683 }
08684
08685
08686 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08687 {
08688
08689 int res;
08690 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08691 res = ast_play_and_wait(chan, "vm-youhaveno");
08692 if (!res)
08693 res = ast_play_and_wait(chan, "vm-messages");
08694 } else {
08695 res = ast_play_and_wait(chan, "vm-youhave");
08696 }
08697 if (!res) {
08698 if (vms->newmessages) {
08699 if (!res) {
08700 if ((vms->newmessages == 1)) {
08701 res = ast_play_and_wait(chan, "digits/1M");
08702 if (!res)
08703 res = ast_play_and_wait(chan, "vm-message");
08704 if (!res)
08705 res = ast_play_and_wait(chan, "vm-INBOXs");
08706 } else {
08707 res = say_and_wait(chan, vms->newmessages, chan->language);
08708 if (!res)
08709 res = ast_play_and_wait(chan, "vm-messages");
08710 if (!res)
08711 res = ast_play_and_wait(chan, "vm-INBOX");
08712 }
08713 }
08714 if (vms->oldmessages && !res)
08715 res = ast_play_and_wait(chan, "vm-and");
08716 }
08717 if (vms->oldmessages) {
08718 if (!res) {
08719 if (vms->oldmessages == 1) {
08720 res = ast_play_and_wait(chan, "digits/1M");
08721 if (!res)
08722 res = ast_play_and_wait(chan, "vm-message");
08723 if (!res)
08724 res = ast_play_and_wait(chan, "vm-Olds");
08725 } else {
08726 res = say_and_wait(chan, vms->oldmessages, chan->language);
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 }
08734 }
08735 return res;
08736 }
08737
08738
08739 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08740
08741 int res;
08742 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08743 res = ast_play_and_wait(chan, "vm-nomessages");
08744 return res;
08745 } else {
08746 res = ast_play_and_wait(chan, "vm-youhave");
08747 }
08748 if (vms->newmessages) {
08749 if (!res)
08750 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08751 if ((vms->newmessages == 1)) {
08752 if (!res)
08753 res = ast_play_and_wait(chan, "vm-message");
08754 if (!res)
08755 res = ast_play_and_wait(chan, "vm-INBOXs");
08756 } else {
08757 if (!res)
08758 res = ast_play_and_wait(chan, "vm-messages");
08759 if (!res)
08760 res = ast_play_and_wait(chan, "vm-INBOX");
08761 }
08762 if (vms->oldmessages && !res)
08763 res = ast_play_and_wait(chan, "vm-and");
08764 }
08765 if (vms->oldmessages) {
08766 if (!res)
08767 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08768 if (vms->oldmessages == 1) {
08769 if (!res)
08770 res = ast_play_and_wait(chan, "vm-message");
08771 if (!res)
08772 res = ast_play_and_wait(chan, "vm-Olds");
08773 } else {
08774 if (!res)
08775 res = ast_play_and_wait(chan, "vm-messages");
08776 if (!res)
08777 res = ast_play_and_wait(chan, "vm-Old");
08778 }
08779 }
08780 return res;
08781 }
08782
08783
08784 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08785 {
08786
08787 int res;
08788 res = ast_play_and_wait(chan, "vm-youhave");
08789 if (!res) {
08790 if (vms->newmessages) {
08791 res = say_and_wait(chan, vms->newmessages, chan->language);
08792 if (!res)
08793 res = ast_play_and_wait(chan, "vm-INBOX");
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 res = ast_play_and_wait(chan, "vm-Old");
08808 if (!res) {
08809 if (vms->oldmessages == 1)
08810 res = ast_play_and_wait(chan, "vm-message");
08811 else
08812 res = ast_play_and_wait(chan, "vm-messages");
08813 }
08814 }
08815 if (!res) {
08816 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08817 res = ast_play_and_wait(chan, "vm-no");
08818 if (!res)
08819 res = ast_play_and_wait(chan, "vm-messages");
08820 }
08821 }
08822 }
08823 return res;
08824 }
08825
08826
08827 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08828 {
08829
08830 int res;
08831 res = ast_play_and_wait(chan, "vm-youhave");
08832 if (!res) {
08833 if (vms->newmessages) {
08834 res = say_and_wait(chan, vms->newmessages, chan->language);
08835 if (!res) {
08836 if (vms->newmessages == 1)
08837 res = ast_play_and_wait(chan, "vm-INBOXs");
08838 else
08839 res = ast_play_and_wait(chan, "vm-INBOX");
08840 }
08841 if (vms->oldmessages && !res)
08842 res = ast_play_and_wait(chan, "vm-and");
08843 else if (!res) {
08844 if ((vms->newmessages == 1))
08845 res = ast_play_and_wait(chan, "vm-message");
08846 else
08847 res = ast_play_and_wait(chan, "vm-messages");
08848 }
08849
08850 }
08851 if (!res && vms->oldmessages) {
08852 res = say_and_wait(chan, vms->oldmessages, chan->language);
08853 if (!res) {
08854 if (vms->oldmessages == 1)
08855 res = ast_play_and_wait(chan, "vm-Olds");
08856 else
08857 res = ast_play_and_wait(chan, "vm-Old");
08858 }
08859 if (!res) {
08860 if (vms->oldmessages == 1)
08861 res = ast_play_and_wait(chan, "vm-message");
08862 else
08863 res = ast_play_and_wait(chan, "vm-messages");
08864 }
08865 }
08866 if (!res) {
08867 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08868 res = ast_play_and_wait(chan, "vm-no");
08869 if (!res)
08870 res = ast_play_and_wait(chan, "vm-messages");
08871 }
08872 }
08873 }
08874 return res;
08875 }
08876
08877
08878 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08879 {
08880
08881 int res;
08882 res = ast_play_and_wait(chan, "vm-youhave");
08883 if (!res) {
08884 if (vms->newmessages) {
08885 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08886 if (!res) {
08887 if ((vms->newmessages == 1)) {
08888 res = ast_play_and_wait(chan, "vm-message");
08889 if (!res)
08890 res = ast_play_and_wait(chan, "vm-INBOXs");
08891 } else {
08892 res = ast_play_and_wait(chan, "vm-messages");
08893 if (!res)
08894 res = ast_play_and_wait(chan, "vm-INBOX");
08895 }
08896 }
08897 if (vms->oldmessages && !res)
08898 res = ast_play_and_wait(chan, "vm-and");
08899 }
08900 if (!res && vms->oldmessages) {
08901 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08902 if (!res) {
08903 if (vms->oldmessages == 1) {
08904 res = ast_play_and_wait(chan, "vm-message");
08905 if (!res)
08906 res = ast_play_and_wait(chan, "vm-Olds");
08907 } else {
08908 res = ast_play_and_wait(chan, "vm-messages");
08909 if (!res)
08910 res = ast_play_and_wait(chan, "vm-Old");
08911 }
08912 }
08913 }
08914 if (!res) {
08915 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08916 res = ast_play_and_wait(chan, "vm-no");
08917 if (!res)
08918 res = ast_play_and_wait(chan, "vm-messages");
08919 }
08920 }
08921 }
08922 return res;
08923 }
08924
08925
08926
08927
08928
08929
08930
08931
08932
08933
08934
08935
08936
08937
08938
08939
08940
08941 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08942 {
08943 int res;
08944 res = ast_play_and_wait(chan, "vm-youhave");
08945 if (!res) {
08946 if (vms->newmessages) {
08947 if (vms->newmessages == 1) {
08948 res = ast_play_and_wait(chan, "digits/jednu");
08949 } else {
08950 res = say_and_wait(chan, vms->newmessages, chan->language);
08951 }
08952 if (!res) {
08953 if ((vms->newmessages == 1))
08954 res = ast_play_and_wait(chan, "vm-novou");
08955 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08956 res = ast_play_and_wait(chan, "vm-nove");
08957 if (vms->newmessages > 4)
08958 res = ast_play_and_wait(chan, "vm-novych");
08959 }
08960 if (vms->oldmessages && !res)
08961 res = ast_play_and_wait(chan, "vm-and");
08962 else if (!res) {
08963 if ((vms->newmessages == 1))
08964 res = ast_play_and_wait(chan, "vm-zpravu");
08965 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08966 res = ast_play_and_wait(chan, "vm-zpravy");
08967 if (vms->newmessages > 4)
08968 res = ast_play_and_wait(chan, "vm-zprav");
08969 }
08970 }
08971 if (!res && vms->oldmessages) {
08972 res = say_and_wait(chan, vms->oldmessages, chan->language);
08973 if (!res) {
08974 if ((vms->oldmessages == 1))
08975 res = ast_play_and_wait(chan, "vm-starou");
08976 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08977 res = ast_play_and_wait(chan, "vm-stare");
08978 if (vms->oldmessages > 4)
08979 res = ast_play_and_wait(chan, "vm-starych");
08980 }
08981 if (!res) {
08982 if ((vms->oldmessages == 1))
08983 res = ast_play_and_wait(chan, "vm-zpravu");
08984 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08985 res = ast_play_and_wait(chan, "vm-zpravy");
08986 if (vms->oldmessages > 4)
08987 res = ast_play_and_wait(chan, "vm-zprav");
08988 }
08989 }
08990 if (!res) {
08991 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08992 res = ast_play_and_wait(chan, "vm-no");
08993 if (!res)
08994 res = ast_play_and_wait(chan, "vm-zpravy");
08995 }
08996 }
08997 }
08998 return res;
08999 }
09000
09001
09002 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
09003 {
09004 int res;
09005
09006 res = ast_play_and_wait(chan, "vm-you");
09007
09008 if (!res && vms->newmessages) {
09009 res = ast_play_and_wait(chan, "vm-have");
09010 if (!res)
09011 res = say_and_wait(chan, vms->newmessages, chan->language);
09012 if (!res)
09013 res = ast_play_and_wait(chan, "vm-tong");
09014 if (!res)
09015 res = ast_play_and_wait(chan, "vm-INBOX");
09016 if (vms->oldmessages && !res)
09017 res = ast_play_and_wait(chan, "vm-and");
09018 else if (!res)
09019 res = ast_play_and_wait(chan, "vm-messages");
09020 }
09021 if (!res && vms->oldmessages) {
09022 res = ast_play_and_wait(chan, "vm-have");
09023 if (!res)
09024 res = say_and_wait(chan, vms->oldmessages, chan->language);
09025 if (!res)
09026 res = ast_play_and_wait(chan, "vm-tong");
09027 if (!res)
09028 res = ast_play_and_wait(chan, "vm-Old");
09029 if (!res)
09030 res = ast_play_and_wait(chan, "vm-messages");
09031 }
09032 if (!res && !vms->oldmessages && !vms->newmessages) {
09033 res = ast_play_and_wait(chan, "vm-haveno");
09034 if (!res)
09035 res = ast_play_and_wait(chan, "vm-messages");
09036 }
09037 return res;
09038 }
09039
09040
09041 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09042 {
09043 int res;
09044
09045
09046 res = ast_play_and_wait(chan, "vm-youhave");
09047 if (!res) {
09048 if (vms->newmessages) {
09049 res = say_and_wait(chan, vms->newmessages, chan->language);
09050 if (!res)
09051 res = ast_play_and_wait(chan, "vm-INBOX");
09052 if (vms->oldmessages && !res)
09053 res = ast_play_and_wait(chan, "vm-and");
09054 }
09055 if (!res && vms->oldmessages) {
09056 res = say_and_wait(chan, vms->oldmessages, chan->language);
09057 if (!res)
09058 res = ast_play_and_wait(chan, "vm-Old");
09059 }
09060 if (!res) {
09061 if (!vms->oldmessages && !vms->newmessages) {
09062 res = ast_play_and_wait(chan, "vm-no");
09063 if (!res)
09064 res = ast_play_and_wait(chan, "vm-message");
09065 }
09066 }
09067 }
09068 return res;
09069 }
09070
09071 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09072 {
09073 char prefile[256];
09074
09075
09076 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09077 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09078 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09079 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09080 ast_play_and_wait(chan, "vm-tempgreetactive");
09081 }
09082 DISPOSE(prefile, -1);
09083 }
09084
09085
09086 if (0) {
09087 return 0;
09088 } else if (!strncasecmp(chan->language, "cs", 2)) {
09089 return vm_intro_cs(chan, vms);
09090 } else if (!strncasecmp(chan->language, "cz", 2)) {
09091 static int deprecation_warning = 0;
09092 if (deprecation_warning++ % 10 == 0) {
09093 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09094 }
09095 return vm_intro_cs(chan, vms);
09096 } else if (!strncasecmp(chan->language, "de", 2)) {
09097 return vm_intro_de(chan, vms);
09098 } else if (!strncasecmp(chan->language, "es", 2)) {
09099 return vm_intro_es(chan, vms);
09100 } else if (!strncasecmp(chan->language, "fr", 2)) {
09101 return vm_intro_fr(chan, vms);
09102 } else if (!strncasecmp(chan->language, "gr", 2)) {
09103 return vm_intro_gr(chan, vms);
09104 } else if (!strncasecmp(chan->language, "he", 2)) {
09105 return vm_intro_he(chan, vms);
09106 } else if (!strncasecmp(chan->language, "it", 2)) {
09107 return vm_intro_it(chan, vms);
09108 } else if (!strncasecmp(chan->language, "nl", 2)) {
09109 return vm_intro_nl(chan, vms);
09110 } else if (!strncasecmp(chan->language, "no", 2)) {
09111 return vm_intro_no(chan, vms);
09112 } else if (!strncasecmp(chan->language, "pl", 2)) {
09113 return vm_intro_pl(chan, vms);
09114 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09115 return vm_intro_pt_BR(chan, vms);
09116 } else if (!strncasecmp(chan->language, "pt", 2)) {
09117 return vm_intro_pt(chan, vms);
09118 } else if (!strncasecmp(chan->language, "ru", 2)) {
09119 return vm_intro_multilang(chan, vms, "n");
09120 } else if (!strncasecmp(chan->language, "se", 2)) {
09121 return vm_intro_se(chan, vms);
09122 } else if (!strncasecmp(chan->language, "ua", 2)) {
09123 return vm_intro_multilang(chan, vms, "n");
09124 } else if (!strncasecmp(chan->language, "vi", 2)) {
09125 return vm_intro_vi(chan, vms);
09126 } else if (!strncasecmp(chan->language, "zh", 2)) {
09127 return vm_intro_zh(chan, vms);
09128 } else {
09129 return vm_intro_en(chan, vms);
09130 }
09131 }
09132
09133 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09134 {
09135 int res = 0;
09136
09137 while (!res) {
09138 if (vms->starting) {
09139 if (vms->lastmsg > -1) {
09140 if (skipadvanced)
09141 res = ast_play_and_wait(chan, "vm-onefor-full");
09142 else
09143 res = ast_play_and_wait(chan, "vm-onefor");
09144 if (!res)
09145 res = vm_play_folder_name(chan, vms->vmbox);
09146 }
09147 if (!res) {
09148 if (skipadvanced)
09149 res = ast_play_and_wait(chan, "vm-opts-full");
09150 else
09151 res = ast_play_and_wait(chan, "vm-opts");
09152 }
09153 } else {
09154
09155 if (skipadvanced) {
09156 res = ast_play_and_wait(chan, "vm-onefor-full");
09157 if (!res)
09158 res = vm_play_folder_name(chan, vms->vmbox);
09159 res = ast_play_and_wait(chan, "vm-opts-full");
09160 }
09161
09162
09163
09164
09165
09166
09167 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09168 res = ast_play_and_wait(chan, "vm-prev");
09169 }
09170 if (!res && !skipadvanced)
09171 res = ast_play_and_wait(chan, "vm-advopts");
09172 if (!res)
09173 res = ast_play_and_wait(chan, "vm-repeat");
09174
09175
09176
09177
09178
09179
09180 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09181 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09182 res = ast_play_and_wait(chan, "vm-next");
09183 }
09184 if (!res) {
09185 int curmsg_deleted;
09186 #ifdef IMAP_STORAGE
09187 ast_mutex_lock(&vms->lock);
09188 #endif
09189 curmsg_deleted = vms->deleted[vms->curmsg];
09190 #ifdef IMAP_STORAGE
09191 ast_mutex_unlock(&vms->lock);
09192 #endif
09193 if (!curmsg_deleted) {
09194 res = ast_play_and_wait(chan, "vm-delete");
09195 } else {
09196 res = ast_play_and_wait(chan, "vm-undelete");
09197 }
09198 if (!res) {
09199 res = ast_play_and_wait(chan, "vm-toforward");
09200 }
09201 if (!res) {
09202 res = ast_play_and_wait(chan, "vm-savemessage");
09203 }
09204 }
09205 }
09206 if (!res) {
09207 res = ast_play_and_wait(chan, "vm-helpexit");
09208 }
09209 if (!res)
09210 res = ast_waitfordigit(chan, 6000);
09211 if (!res) {
09212 vms->repeats++;
09213 if (vms->repeats > 2) {
09214 res = 't';
09215 }
09216 }
09217 }
09218 return res;
09219 }
09220
09221 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09222 {
09223 int res = 0;
09224
09225 while (!res) {
09226 if (vms->lastmsg > -1) {
09227 res = ast_play_and_wait(chan, "vm-listen");
09228 if (!res)
09229 res = vm_play_folder_name(chan, vms->vmbox);
09230 if (!res)
09231 res = ast_play_and_wait(chan, "press");
09232 if (!res)
09233 res = ast_play_and_wait(chan, "digits/1");
09234 }
09235 if (!res)
09236 res = ast_play_and_wait(chan, "vm-opts");
09237 if (!res) {
09238 vms->starting = 0;
09239 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09240 }
09241 }
09242 return res;
09243 }
09244
09245 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09246 {
09247 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09248 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09249 } else {
09250 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09251 }
09252 }
09253
09254
09255 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09256 {
09257 int cmd = 0;
09258 int duration = 0;
09259 int tries = 0;
09260 char newpassword[80] = "";
09261 char newpassword2[80] = "";
09262 char prefile[PATH_MAX] = "";
09263 unsigned char buf[256];
09264 int bytes = 0;
09265
09266 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09267 if (ast_adsi_available(chan)) {
09268 bytes += adsi_logo(buf + bytes);
09269 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09270 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09271 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09272 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09273 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09274 }
09275
09276
09277 if (ast_test_flag(vmu, VM_FORCENAME)) {
09278 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09279 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09280 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09281 if (cmd < 0 || cmd == 't' || cmd == '#')
09282 return cmd;
09283 }
09284 }
09285
09286
09287 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09288 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09289 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09290 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09291 if (cmd < 0 || cmd == 't' || cmd == '#')
09292 return cmd;
09293 }
09294
09295 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09296 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09297 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09298 if (cmd < 0 || cmd == 't' || cmd == '#')
09299 return cmd;
09300 }
09301 }
09302
09303
09304
09305
09306
09307 for (;;) {
09308 newpassword[1] = '\0';
09309 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09310 if (cmd == '#')
09311 newpassword[0] = '\0';
09312 if (cmd < 0 || cmd == 't' || cmd == '#')
09313 return cmd;
09314 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09315 if (cmd < 0 || cmd == 't' || cmd == '#')
09316 return cmd;
09317 cmd = check_password(vmu, newpassword);
09318 if (cmd != 0) {
09319 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09320 cmd = ast_play_and_wait(chan, vm_invalid_password);
09321 } else {
09322 newpassword2[1] = '\0';
09323 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09324 if (cmd == '#')
09325 newpassword2[0] = '\0';
09326 if (cmd < 0 || cmd == 't' || cmd == '#')
09327 return cmd;
09328 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09329 if (cmd < 0 || cmd == 't' || cmd == '#')
09330 return cmd;
09331 if (!strcmp(newpassword, newpassword2))
09332 break;
09333 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09334 cmd = ast_play_and_wait(chan, vm_mismatch);
09335 }
09336 if (++tries == 3)
09337 return -1;
09338 if (cmd != 0) {
09339 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09340 }
09341 }
09342 if (pwdchange & PWDCHANGE_INTERNAL)
09343 vm_change_password(vmu, newpassword);
09344 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09345 vm_change_password_shell(vmu, newpassword);
09346
09347 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09348 cmd = ast_play_and_wait(chan, vm_passchanged);
09349
09350 return cmd;
09351 }
09352
09353 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09354 {
09355 int cmd = 0;
09356 int retries = 0;
09357 int duration = 0;
09358 char newpassword[80] = "";
09359 char newpassword2[80] = "";
09360 char prefile[PATH_MAX] = "";
09361 unsigned char buf[256];
09362 int bytes = 0;
09363
09364 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09365 if (ast_adsi_available(chan)) {
09366 bytes += adsi_logo(buf + bytes);
09367 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09368 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09369 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09370 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09371 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09372 }
09373 while ((cmd >= 0) && (cmd != 't')) {
09374 if (cmd)
09375 retries = 0;
09376 switch (cmd) {
09377 case '1':
09378 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09379 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09380 break;
09381 case '2':
09382 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09383 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09384 break;
09385 case '3':
09386 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09387 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09388 break;
09389 case '4':
09390 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09391 break;
09392 case '5':
09393 if (vmu->password[0] == '-') {
09394 cmd = ast_play_and_wait(chan, "vm-no");
09395 break;
09396 }
09397 newpassword[1] = '\0';
09398 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09399 if (cmd == '#')
09400 newpassword[0] = '\0';
09401 else {
09402 if (cmd < 0)
09403 break;
09404 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09405 break;
09406 }
09407 }
09408 cmd = check_password(vmu, newpassword);
09409 if (cmd != 0) {
09410 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09411 cmd = ast_play_and_wait(chan, vm_invalid_password);
09412 if (!cmd) {
09413 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09414 }
09415 break;
09416 }
09417 newpassword2[1] = '\0';
09418 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09419 if (cmd == '#')
09420 newpassword2[0] = '\0';
09421 else {
09422 if (cmd < 0)
09423 break;
09424
09425 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09426 break;
09427 }
09428 }
09429 if (strcmp(newpassword, newpassword2)) {
09430 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09431 cmd = ast_play_and_wait(chan, vm_mismatch);
09432 if (!cmd) {
09433 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09434 }
09435 break;
09436 }
09437
09438 if (pwdchange & PWDCHANGE_INTERNAL) {
09439 vm_change_password(vmu, newpassword);
09440 }
09441 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09442 vm_change_password_shell(vmu, newpassword);
09443 }
09444
09445 ast_debug(1, "User %s set password to %s of length %d\n",
09446 vms->username, newpassword, (int) strlen(newpassword));
09447 cmd = ast_play_and_wait(chan, vm_passchanged);
09448 break;
09449 case '*':
09450 cmd = 't';
09451 break;
09452 default:
09453 cmd = 0;
09454 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09455 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09456 if (ast_fileexists(prefile, NULL, NULL)) {
09457 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09458 }
09459 DISPOSE(prefile, -1);
09460 if (!cmd) {
09461 cmd = ast_play_and_wait(chan, "vm-options");
09462 }
09463 if (!cmd) {
09464 cmd = ast_waitfordigit(chan, 6000);
09465 }
09466 if (!cmd) {
09467 retries++;
09468 }
09469 if (retries > 3) {
09470 cmd = 't';
09471 }
09472 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09473 }
09474 }
09475 if (cmd == 't')
09476 cmd = 0;
09477 return cmd;
09478 }
09479
09480
09481
09482
09483
09484
09485
09486
09487
09488
09489
09490
09491
09492
09493
09494
09495
09496 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09497 {
09498 int cmd = 0;
09499 int retries = 0;
09500 int duration = 0;
09501 char prefile[PATH_MAX] = "";
09502 unsigned char buf[256];
09503 int bytes = 0;
09504
09505 if (ast_adsi_available(chan)) {
09506 bytes += adsi_logo(buf + bytes);
09507 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09508 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09509 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09510 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09511 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09512 }
09513
09514 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09515 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09516 while ((cmd >= 0) && (cmd != 't')) {
09517 if (cmd)
09518 retries = 0;
09519 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09520 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09521 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09522 if (cmd == -1) {
09523 break;
09524 }
09525 cmd = 't';
09526 } else {
09527 switch (cmd) {
09528 case '1':
09529 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09530 break;
09531 case '2':
09532 DELETE(prefile, -1, prefile, vmu);
09533 ast_play_and_wait(chan, "vm-tempremoved");
09534 cmd = 't';
09535 break;
09536 case '*':
09537 cmd = 't';
09538 break;
09539 default:
09540 cmd = ast_play_and_wait(chan,
09541 ast_fileexists(prefile, NULL, NULL) > 0 ?
09542 "vm-tempgreeting2" : "vm-tempgreeting");
09543 if (!cmd) {
09544 cmd = ast_waitfordigit(chan, 6000);
09545 }
09546 if (!cmd) {
09547 retries++;
09548 }
09549 if (retries > 3) {
09550 cmd = 't';
09551 }
09552 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09553 }
09554 }
09555 DISPOSE(prefile, -1);
09556 }
09557 if (cmd == 't')
09558 cmd = 0;
09559 return cmd;
09560 }
09561
09562
09563
09564
09565
09566
09567
09568
09569
09570 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09571 {
09572 int cmd = 0;
09573
09574 if (vms->lastmsg > -1) {
09575 cmd = play_message(chan, vmu, vms);
09576 } else {
09577 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09578 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09579 if (!cmd) {
09580 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09581 cmd = ast_play_and_wait(chan, vms->fn);
09582 }
09583 if (!cmd)
09584 cmd = ast_play_and_wait(chan, "vm-messages");
09585 } else {
09586 if (!cmd)
09587 cmd = ast_play_and_wait(chan, "vm-messages");
09588 if (!cmd) {
09589 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09590 cmd = ast_play_and_wait(chan, vms->fn);
09591 }
09592 }
09593 }
09594 return cmd;
09595 }
09596
09597
09598 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09599 {
09600 int cmd = 0;
09601
09602 if (vms->lastmsg > -1) {
09603 cmd = play_message(chan, vmu, vms);
09604 } else {
09605 if (!strcasecmp(vms->fn, "INBOX")) {
09606 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09607 } else {
09608 cmd = ast_play_and_wait(chan, "vm-nomessages");
09609 }
09610 }
09611 return cmd;
09612 }
09613
09614
09615
09616
09617
09618
09619
09620
09621
09622 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09623 {
09624 int cmd = 0;
09625
09626 if (vms->lastmsg > -1) {
09627 cmd = play_message(chan, vmu, vms);
09628 } else {
09629 cmd = ast_play_and_wait(chan, "vm-youhave");
09630 if (!cmd)
09631 cmd = ast_play_and_wait(chan, "vm-no");
09632 if (!cmd) {
09633 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09634 cmd = ast_play_and_wait(chan, vms->fn);
09635 }
09636 if (!cmd)
09637 cmd = ast_play_and_wait(chan, "vm-messages");
09638 }
09639 return cmd;
09640 }
09641
09642
09643
09644
09645
09646
09647
09648
09649
09650 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09651 {
09652 int cmd;
09653
09654 if (vms->lastmsg > -1) {
09655 cmd = play_message(chan, vmu, vms);
09656 } else {
09657 cmd = ast_play_and_wait(chan, "vm-no");
09658 if (!cmd)
09659 cmd = ast_play_and_wait(chan, "vm-message");
09660 if (!cmd) {
09661 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09662 cmd = ast_play_and_wait(chan, vms->fn);
09663 }
09664 }
09665 return cmd;
09666 }
09667
09668
09669
09670
09671
09672
09673
09674
09675
09676 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09677 {
09678 int cmd;
09679
09680 if (vms->lastmsg > -1) {
09681 cmd = play_message(chan, vmu, vms);
09682 } else {
09683 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09684 if (!cmd)
09685 cmd = ast_play_and_wait(chan, "vm-messages");
09686 if (!cmd) {
09687 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09688 cmd = ast_play_and_wait(chan, vms->fn);
09689 }
09690 }
09691 return cmd;
09692 }
09693
09694
09695
09696
09697
09698
09699
09700
09701
09702 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09703 {
09704 int cmd;
09705
09706 if (vms->lastmsg > -1) {
09707 cmd = play_message(chan, vmu, vms);
09708 } else {
09709 cmd = ast_play_and_wait(chan, "vm-no");
09710 if (!cmd) {
09711 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09712 cmd = ast_play_and_wait(chan, vms->fn);
09713 }
09714 if (!cmd)
09715 cmd = ast_play_and_wait(chan, "vm-messages");
09716 }
09717 return cmd;
09718 }
09719
09720
09721
09722
09723
09724
09725
09726
09727
09728 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09729 {
09730 int cmd;
09731
09732 if (vms->lastmsg > -1) {
09733 cmd = play_message(chan, vmu, vms);
09734 } else {
09735 cmd = ast_play_and_wait(chan, "vm-you");
09736 if (!cmd)
09737 cmd = ast_play_and_wait(chan, "vm-haveno");
09738 if (!cmd)
09739 cmd = ast_play_and_wait(chan, "vm-messages");
09740 if (!cmd) {
09741 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09742 cmd = ast_play_and_wait(chan, vms->fn);
09743 }
09744 }
09745 return cmd;
09746 }
09747
09748
09749
09750
09751
09752
09753
09754
09755
09756 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09757 {
09758 int cmd = 0;
09759
09760 if (vms->lastmsg > -1) {
09761 cmd = play_message(chan, vmu, vms);
09762 } else {
09763 cmd = ast_play_and_wait(chan, "vm-no");
09764 if (!cmd) {
09765 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09766 cmd = ast_play_and_wait(chan, vms->fn);
09767 }
09768 }
09769 return cmd;
09770 }
09771
09772
09773
09774
09775
09776
09777
09778
09779
09780
09781
09782
09783 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09784 {
09785 if (!strncasecmp(chan->language, "es", 2)) {
09786 return vm_browse_messages_es(chan, vms, vmu);
09787 } else if (!strncasecmp(chan->language, "gr", 2)) {
09788 return vm_browse_messages_gr(chan, vms, vmu);
09789 } else if (!strncasecmp(chan->language, "he", 2)) {
09790 return vm_browse_messages_he(chan, vms, vmu);
09791 } else if (!strncasecmp(chan->language, "it", 2)) {
09792 return vm_browse_messages_it(chan, vms, vmu);
09793 } else if (!strncasecmp(chan->language, "pt", 2)) {
09794 return vm_browse_messages_pt(chan, vms, vmu);
09795 } else if (!strncasecmp(chan->language, "vi", 2)) {
09796 return vm_browse_messages_vi(chan, vms, vmu);
09797 } else if (!strncasecmp(chan->language, "zh", 2)) {
09798 return vm_browse_messages_zh(chan, vms, vmu);
09799 } else {
09800 return vm_browse_messages_en(chan, vms, vmu);
09801 }
09802 }
09803
09804 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09805 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09806 int skipuser, int max_logins, int silent)
09807 {
09808 int useadsi = 0, valid = 0, logretries = 0;
09809 char password[AST_MAX_EXTENSION]="", *passptr;
09810 struct ast_vm_user vmus, *vmu = NULL;
09811
09812
09813 adsi_begin(chan, &useadsi);
09814 if (!skipuser && useadsi)
09815 adsi_login(chan);
09816 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09817 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09818 return -1;
09819 }
09820
09821
09822
09823 while (!valid && (logretries < max_logins)) {
09824
09825 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09826 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09827 return -1;
09828 }
09829 if (ast_strlen_zero(mailbox)) {
09830 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09831 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09832 } else {
09833 ast_verb(3, "Username not entered\n");
09834 return -1;
09835 }
09836 } else if (mailbox[0] == '*') {
09837
09838 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09839 if (ast_exists_extension(chan, chan->context, "a", 1,
09840 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09841 return -1;
09842 }
09843 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09844 mailbox[0] = '\0';
09845 }
09846
09847 if (useadsi)
09848 adsi_password(chan);
09849
09850 if (!ast_strlen_zero(prefix)) {
09851 char fullusername[80] = "";
09852 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09853 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09854 ast_copy_string(mailbox, fullusername, mailbox_size);
09855 }
09856
09857 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09858 vmu = find_user(&vmus, context, mailbox);
09859 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09860
09861 password[0] = '\0';
09862 } else {
09863 if (ast_streamfile(chan, vm_password, chan->language)) {
09864 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09865 return -1;
09866 }
09867 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09868 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09869 return -1;
09870 } else if (password[0] == '*') {
09871
09872 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09873 if (ast_exists_extension(chan, chan->context, "a", 1,
09874 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09875 mailbox[0] = '*';
09876 return -1;
09877 }
09878 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09879 mailbox[0] = '\0';
09880
09881 vmu = NULL;
09882 }
09883 }
09884
09885 if (vmu) {
09886 passptr = vmu->password;
09887 if (passptr[0] == '-') passptr++;
09888 }
09889 if (vmu && !strcmp(passptr, password))
09890 valid++;
09891 else {
09892 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09893 if (!ast_strlen_zero(prefix))
09894 mailbox[0] = '\0';
09895 }
09896 logretries++;
09897 if (!valid) {
09898 if (skipuser || logretries >= max_logins) {
09899 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09900 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09901 return -1;
09902 }
09903 } else {
09904 if (useadsi)
09905 adsi_login(chan);
09906 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09907 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09908 return -1;
09909 }
09910 }
09911 if (ast_waitstream(chan, ""))
09912 return -1;
09913 }
09914 }
09915 if (!valid && (logretries >= max_logins)) {
09916 ast_stopstream(chan);
09917 ast_play_and_wait(chan, "vm-goodbye");
09918 return -1;
09919 }
09920 if (vmu && !skipuser) {
09921 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09922 }
09923 return 0;
09924 }
09925
09926 static int vm_execmain(struct ast_channel *chan, const char *data)
09927 {
09928
09929
09930
09931 int res = -1;
09932 int cmd = 0;
09933 int valid = 0;
09934 char prefixstr[80] ="";
09935 char ext_context[256]="";
09936 int box;
09937 int useadsi = 0;
09938 int skipuser = 0;
09939 struct vm_state vms;
09940 struct ast_vm_user *vmu = NULL, vmus;
09941 char *context = NULL;
09942 int silentexit = 0;
09943 struct ast_flags flags = { 0 };
09944 signed char record_gain = 0;
09945 int play_auto = 0;
09946 int play_folder = 0;
09947 int in_urgent = 0;
09948 #ifdef IMAP_STORAGE
09949 int deleted = 0;
09950 #endif
09951
09952
09953 memset(&vms, 0, sizeof(vms));
09954
09955 vms.lastmsg = -1;
09956
09957 memset(&vmus, 0, sizeof(vmus));
09958
09959 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09960 if (chan->_state != AST_STATE_UP) {
09961 ast_debug(1, "Before ast_answer\n");
09962 ast_answer(chan);
09963 }
09964
09965 if (!ast_strlen_zero(data)) {
09966 char *opts[OPT_ARG_ARRAY_SIZE];
09967 char *parse;
09968 AST_DECLARE_APP_ARGS(args,
09969 AST_APP_ARG(argv0);
09970 AST_APP_ARG(argv1);
09971 );
09972
09973 parse = ast_strdupa(data);
09974
09975 AST_STANDARD_APP_ARGS(args, parse);
09976
09977 if (args.argc == 2) {
09978 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09979 return -1;
09980 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09981 int gain;
09982 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09983 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09984 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09985 return -1;
09986 } else {
09987 record_gain = (signed char) gain;
09988 }
09989 } else {
09990 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09991 }
09992 }
09993 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09994 play_auto = 1;
09995 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09996
09997 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09998 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09999 play_folder = -1;
10000 }
10001 } else {
10002 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
10003 }
10004 } else {
10005 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
10006 }
10007 if (play_folder > 9 || play_folder < 0) {
10008 ast_log(AST_LOG_WARNING,
10009 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
10010 opts[OPT_ARG_PLAYFOLDER]);
10011 play_folder = 0;
10012 }
10013 }
10014 } else {
10015
10016 while (*(args.argv0)) {
10017 if (*(args.argv0) == 's')
10018 ast_set_flag(&flags, OPT_SILENT);
10019 else if (*(args.argv0) == 'p')
10020 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
10021 else
10022 break;
10023 (args.argv0)++;
10024 }
10025
10026 }
10027
10028 valid = ast_test_flag(&flags, OPT_SILENT);
10029
10030 if ((context = strchr(args.argv0, '@')))
10031 *context++ = '\0';
10032
10033 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10034 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10035 else
10036 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10037
10038 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10039 skipuser++;
10040 else
10041 valid = 0;
10042 }
10043
10044 if (!valid)
10045 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10046
10047 ast_debug(1, "After vm_authenticate\n");
10048
10049 if (vms.username[0] == '*') {
10050 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10051
10052
10053 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10054 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10055 res = 0;
10056 goto out;
10057 }
10058 }
10059
10060 if (!res) {
10061 valid = 1;
10062 if (!skipuser)
10063 vmu = &vmus;
10064 } else {
10065 res = 0;
10066 }
10067
10068
10069 adsi_begin(chan, &useadsi);
10070
10071 ast_test_suite_assert(valid);
10072 if (!valid) {
10073 goto out;
10074 }
10075 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10076
10077 #ifdef IMAP_STORAGE
10078 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10079 pthread_setspecific(ts_vmstate.key, &vms);
10080
10081 vms.interactive = 1;
10082 vms.updated = 1;
10083 if (vmu)
10084 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10085 vmstate_insert(&vms);
10086 init_vm_state(&vms);
10087 #endif
10088
10089
10090 if (!ast_strlen_zero(vmu->language))
10091 ast_string_field_set(chan, language, vmu->language);
10092
10093
10094 ast_debug(1, "Before open_mailbox\n");
10095 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10096 if (res < 0)
10097 goto out;
10098 vms.oldmessages = vms.lastmsg + 1;
10099 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10100
10101 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10102 if (res < 0)
10103 goto out;
10104 vms.newmessages = vms.lastmsg + 1;
10105 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10106
10107 in_urgent = 1;
10108 res = open_mailbox(&vms, vmu, 11);
10109 if (res < 0)
10110 goto out;
10111 vms.urgentmessages = vms.lastmsg + 1;
10112 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10113
10114
10115 if (play_auto) {
10116 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10117 if (vms.urgentmessages) {
10118 in_urgent = 1;
10119 res = open_mailbox(&vms, vmu, 11);
10120 } else {
10121 in_urgent = 0;
10122 res = open_mailbox(&vms, vmu, play_folder);
10123 }
10124 if (res < 0)
10125 goto out;
10126
10127
10128 if (vms.lastmsg == -1) {
10129 in_urgent = 0;
10130 cmd = vm_browse_messages(chan, &vms, vmu);
10131 res = 0;
10132 goto out;
10133 }
10134 } else {
10135 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10136
10137 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10138 in_urgent = 0;
10139 play_folder = 1;
10140 if (res < 0)
10141 goto out;
10142 } else if (!vms.urgentmessages && vms.newmessages) {
10143
10144 in_urgent = 0;
10145 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10146 if (res < 0)
10147 goto out;
10148 }
10149 }
10150
10151 if (useadsi)
10152 adsi_status(chan, &vms);
10153 res = 0;
10154
10155
10156 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10157 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10158 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10159 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10160 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10161 if ((cmd == 't') || (cmd == '#')) {
10162
10163 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10164 res = 0;
10165 goto out;
10166 } else if (cmd < 0) {
10167
10168 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10169 res = -1;
10170 goto out;
10171 }
10172 }
10173 #ifdef IMAP_STORAGE
10174 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10175 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10176 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10177 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10178 }
10179 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10180 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10181 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10182 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10183 }
10184 #endif
10185
10186 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10187 if (play_auto) {
10188 cmd = '1';
10189 } else {
10190 cmd = vm_intro(chan, vmu, &vms);
10191 }
10192 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10193
10194 vms.repeats = 0;
10195 vms.starting = 1;
10196 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10197
10198 switch (cmd) {
10199 case '1':
10200 vms.curmsg = 0;
10201
10202 case '5':
10203 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10204 cmd = vm_browse_messages(chan, &vms, vmu);
10205 break;
10206 case '2':
10207 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10208 if (useadsi)
10209 adsi_folders(chan, 0, "Change to folder...");
10210
10211 cmd = get_folder2(chan, "vm-changeto", 0);
10212 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10213 if (cmd == '#') {
10214 cmd = 0;
10215 } else if (cmd > 0) {
10216 cmd = cmd - '0';
10217 res = close_mailbox(&vms, vmu);
10218 if (res == ERROR_LOCK_PATH)
10219 goto out;
10220
10221 if (cmd != 11) in_urgent = 0;
10222 res = open_mailbox(&vms, vmu, cmd);
10223 if (res < 0)
10224 goto out;
10225 play_folder = cmd;
10226 cmd = 0;
10227 }
10228 if (useadsi)
10229 adsi_status2(chan, &vms);
10230
10231 if (!cmd) {
10232 cmd = vm_play_folder_name(chan, vms.vmbox);
10233 }
10234
10235 vms.starting = 1;
10236 vms.curmsg = 0;
10237 break;
10238 case '3':
10239 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10240 cmd = 0;
10241 vms.repeats = 0;
10242 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10243 switch (cmd) {
10244 case '1':
10245 if (vms.lastmsg > -1 && !vms.starting) {
10246 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10247 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10248 res = cmd;
10249 goto out;
10250 }
10251 } else {
10252 cmd = ast_play_and_wait(chan, "vm-sorry");
10253 }
10254 cmd = 't';
10255 break;
10256 case '2':
10257 if (!vms.starting)
10258 ast_verb(3, "Callback Requested\n");
10259 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10260 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10261 if (cmd == 9) {
10262 silentexit = 1;
10263 goto out;
10264 } else if (cmd == ERROR_LOCK_PATH) {
10265 res = cmd;
10266 goto out;
10267 }
10268 } else {
10269 cmd = ast_play_and_wait(chan, "vm-sorry");
10270 }
10271 cmd = 't';
10272 break;
10273 case '3':
10274 if (vms.lastmsg > -1 && !vms.starting) {
10275 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10276 if (cmd == ERROR_LOCK_PATH) {
10277 res = cmd;
10278 goto out;
10279 }
10280 } else {
10281 cmd = ast_play_and_wait(chan, "vm-sorry");
10282 }
10283 cmd = 't';
10284 break;
10285 case '4':
10286 if (!ast_strlen_zero(vmu->dialout)) {
10287 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10288 if (cmd == 9) {
10289 silentexit = 1;
10290 goto out;
10291 }
10292 } else {
10293 cmd = ast_play_and_wait(chan, "vm-sorry");
10294 }
10295 cmd = 't';
10296 break;
10297
10298 case '5':
10299 if (ast_test_flag(vmu, VM_SVMAIL)) {
10300 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10301 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10302 res = cmd;
10303 goto out;
10304 }
10305 } else {
10306 cmd = ast_play_and_wait(chan, "vm-sorry");
10307 }
10308 cmd = 't';
10309 break;
10310
10311 case '*':
10312 cmd = 't';
10313 break;
10314
10315 default:
10316 cmd = 0;
10317 if (!vms.starting) {
10318 cmd = ast_play_and_wait(chan, "vm-toreply");
10319 }
10320 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10321 cmd = ast_play_and_wait(chan, "vm-tocallback");
10322 }
10323 if (!cmd && !vms.starting) {
10324 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10325 }
10326 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10327 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10328 }
10329 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10330 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10331 }
10332 if (!cmd) {
10333 cmd = ast_play_and_wait(chan, "vm-starmain");
10334 }
10335 if (!cmd) {
10336 cmd = ast_waitfordigit(chan, 6000);
10337 }
10338 if (!cmd) {
10339 vms.repeats++;
10340 }
10341 if (vms.repeats > 3) {
10342 cmd = 't';
10343 }
10344 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10345 }
10346 }
10347 if (cmd == 't') {
10348 cmd = 0;
10349 vms.repeats = 0;
10350 }
10351 break;
10352 case '4':
10353 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10354 if (vms.curmsg > 0) {
10355 vms.curmsg--;
10356 cmd = play_message(chan, vmu, &vms);
10357 } else {
10358
10359
10360
10361
10362 if (in_urgent == 0 && vms.urgentmessages > 0) {
10363
10364 in_urgent = 1;
10365 res = close_mailbox(&vms, vmu);
10366 if (res == ERROR_LOCK_PATH)
10367 goto out;
10368 res = open_mailbox(&vms, vmu, 11);
10369 if (res < 0)
10370 goto out;
10371 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10372 vms.curmsg = vms.lastmsg;
10373 if (vms.lastmsg < 0) {
10374 cmd = ast_play_and_wait(chan, "vm-nomore");
10375 }
10376 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10377 vms.curmsg = vms.lastmsg;
10378 cmd = play_message(chan, vmu, &vms);
10379 } else {
10380 cmd = ast_play_and_wait(chan, "vm-nomore");
10381 }
10382 }
10383 break;
10384 case '6':
10385 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10386 if (vms.curmsg < vms.lastmsg) {
10387 vms.curmsg++;
10388 cmd = play_message(chan, vmu, &vms);
10389 } else {
10390 if (in_urgent && vms.newmessages > 0) {
10391
10392
10393
10394
10395 in_urgent = 0;
10396 res = close_mailbox(&vms, vmu);
10397 if (res == ERROR_LOCK_PATH)
10398 goto out;
10399 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10400 if (res < 0)
10401 goto out;
10402 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10403 vms.curmsg = -1;
10404 if (vms.lastmsg < 0) {
10405 cmd = ast_play_and_wait(chan, "vm-nomore");
10406 }
10407 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10408 vms.curmsg = 0;
10409 cmd = play_message(chan, vmu, &vms);
10410 } else {
10411 cmd = ast_play_and_wait(chan, "vm-nomore");
10412 }
10413 }
10414 break;
10415 case '7':
10416 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10417 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10418 if (useadsi)
10419 adsi_delete(chan, &vms);
10420 if (vms.deleted[vms.curmsg]) {
10421 if (play_folder == 0) {
10422 if (in_urgent) {
10423 vms.urgentmessages--;
10424 } else {
10425 vms.newmessages--;
10426 }
10427 }
10428 else if (play_folder == 1)
10429 vms.oldmessages--;
10430 cmd = ast_play_and_wait(chan, "vm-deleted");
10431 } else {
10432 if (play_folder == 0) {
10433 if (in_urgent) {
10434 vms.urgentmessages++;
10435 } else {
10436 vms.newmessages++;
10437 }
10438 }
10439 else if (play_folder == 1)
10440 vms.oldmessages++;
10441 cmd = ast_play_and_wait(chan, "vm-undeleted");
10442 }
10443 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10444 if (vms.curmsg < vms.lastmsg) {
10445 vms.curmsg++;
10446 cmd = play_message(chan, vmu, &vms);
10447 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10448 vms.curmsg = 0;
10449 cmd = play_message(chan, vmu, &vms);
10450 } else {
10451
10452
10453
10454
10455 if (in_urgent == 1) {
10456
10457 in_urgent = 0;
10458 res = close_mailbox(&vms, vmu);
10459 if (res == ERROR_LOCK_PATH)
10460 goto out;
10461 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10462 if (res < 0)
10463 goto out;
10464 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10465 vms.curmsg = -1;
10466 if (vms.lastmsg < 0) {
10467 cmd = ast_play_and_wait(chan, "vm-nomore");
10468 }
10469 } else {
10470 cmd = ast_play_and_wait(chan, "vm-nomore");
10471 }
10472 }
10473 }
10474 } else
10475 cmd = 0;
10476 #ifdef IMAP_STORAGE
10477 deleted = 1;
10478 #endif
10479 break;
10480
10481 case '8':
10482 if (vms.lastmsg > -1) {
10483 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10484 if (cmd == ERROR_LOCK_PATH) {
10485 res = cmd;
10486 goto out;
10487 }
10488 } else {
10489
10490
10491
10492
10493 if (in_urgent == 1 && vms.newmessages > 0) {
10494
10495 in_urgent = 0;
10496 res = close_mailbox(&vms, vmu);
10497 if (res == ERROR_LOCK_PATH)
10498 goto out;
10499 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10500 if (res < 0)
10501 goto out;
10502 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10503 vms.curmsg = -1;
10504 if (vms.lastmsg < 0) {
10505 cmd = ast_play_and_wait(chan, "vm-nomore");
10506 }
10507 } else {
10508 cmd = ast_play_and_wait(chan, "vm-nomore");
10509 }
10510 }
10511 break;
10512 case '9':
10513 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10514 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10515
10516 cmd = 0;
10517 break;
10518 }
10519 if (useadsi)
10520 adsi_folders(chan, 1, "Save to folder...");
10521 cmd = get_folder2(chan, "vm-savefolder", 1);
10522 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10523 box = 0;
10524 if (cmd == '#') {
10525 cmd = 0;
10526 break;
10527 } else if (cmd > 0) {
10528 box = cmd = cmd - '0';
10529 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10530 if (cmd == ERROR_LOCK_PATH) {
10531 res = cmd;
10532 goto out;
10533 #ifndef IMAP_STORAGE
10534 } else if (!cmd) {
10535 vms.deleted[vms.curmsg] = 1;
10536 #endif
10537 } else {
10538 vms.deleted[vms.curmsg] = 0;
10539 vms.heard[vms.curmsg] = 0;
10540 }
10541 }
10542 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10543 if (useadsi)
10544 adsi_message(chan, &vms);
10545 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10546 if (!cmd) {
10547 cmd = ast_play_and_wait(chan, "vm-message");
10548 if (!cmd)
10549 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10550 if (!cmd)
10551 cmd = ast_play_and_wait(chan, "vm-savedto");
10552 if (!cmd)
10553 cmd = vm_play_folder_name(chan, vms.fn);
10554 } else {
10555 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10556 }
10557 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10558 if (vms.curmsg < vms.lastmsg) {
10559 vms.curmsg++;
10560 cmd = play_message(chan, vmu, &vms);
10561 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10562 vms.curmsg = 0;
10563 cmd = play_message(chan, vmu, &vms);
10564 } else {
10565
10566
10567
10568
10569 if (in_urgent == 1 && vms.newmessages > 0) {
10570
10571 in_urgent = 0;
10572 res = close_mailbox(&vms, vmu);
10573 if (res == ERROR_LOCK_PATH)
10574 goto out;
10575 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10576 if (res < 0)
10577 goto out;
10578 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10579 vms.curmsg = -1;
10580 if (vms.lastmsg < 0) {
10581 cmd = ast_play_and_wait(chan, "vm-nomore");
10582 }
10583 } else {
10584 cmd = ast_play_and_wait(chan, "vm-nomore");
10585 }
10586 }
10587 }
10588 break;
10589 case '*':
10590 if (!vms.starting) {
10591 cmd = ast_play_and_wait(chan, "vm-onefor");
10592 if (!strncasecmp(chan->language, "he", 2)) {
10593 cmd = ast_play_and_wait(chan, "vm-for");
10594 }
10595 if (!cmd)
10596 cmd = vm_play_folder_name(chan, vms.vmbox);
10597 if (!cmd)
10598 cmd = ast_play_and_wait(chan, "vm-opts");
10599 if (!cmd)
10600 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10601 } else
10602 cmd = 0;
10603 break;
10604 case '0':
10605 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10606 if (useadsi)
10607 adsi_status(chan, &vms);
10608 break;
10609 default:
10610 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10611 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10612 break;
10613 }
10614 }
10615 if ((cmd == 't') || (cmd == '#')) {
10616
10617 res = 0;
10618 } else {
10619
10620 res = -1;
10621 }
10622
10623 out:
10624 if (res > -1) {
10625 ast_stopstream(chan);
10626 adsi_goodbye(chan);
10627 if (valid && res != OPERATOR_EXIT) {
10628 if (silentexit)
10629 res = ast_play_and_wait(chan, "vm-dialout");
10630 else
10631 res = ast_play_and_wait(chan, "vm-goodbye");
10632 }
10633 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10634 res = 0;
10635 }
10636 if (useadsi)
10637 ast_adsi_unload_session(chan);
10638 }
10639 if (vmu)
10640 close_mailbox(&vms, vmu);
10641 if (valid) {
10642 int new = 0, old = 0, urgent = 0;
10643 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10644 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10645
10646 run_externnotify(vmu->context, vmu->mailbox, NULL);
10647 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10648 queue_mwi_event(ext_context, urgent, new, old);
10649 }
10650 #ifdef IMAP_STORAGE
10651
10652 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10653 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10654 ast_mutex_lock(&vms.lock);
10655 #ifdef HAVE_IMAP_TK2006
10656 if (LEVELUIDPLUS (vms.mailstream)) {
10657 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10658 } else
10659 #endif
10660 mail_expunge(vms.mailstream);
10661 ast_mutex_unlock(&vms.lock);
10662 }
10663
10664
10665 if (vmu) {
10666 vmstate_delete(&vms);
10667 }
10668 #endif
10669 if (vmu)
10670 free_user(vmu);
10671
10672 #ifdef IMAP_STORAGE
10673 pthread_setspecific(ts_vmstate.key, NULL);
10674 #endif
10675 return res;
10676 }
10677
10678 static int vm_exec(struct ast_channel *chan, const char *data)
10679 {
10680 int res = 0;
10681 char *tmp;
10682 struct leave_vm_options leave_options;
10683 struct ast_flags flags = { 0 };
10684 char *opts[OPT_ARG_ARRAY_SIZE];
10685 AST_DECLARE_APP_ARGS(args,
10686 AST_APP_ARG(argv0);
10687 AST_APP_ARG(argv1);
10688 );
10689
10690 memset(&leave_options, 0, sizeof(leave_options));
10691
10692 if (chan->_state != AST_STATE_UP)
10693 ast_answer(chan);
10694
10695 if (!ast_strlen_zero(data)) {
10696 tmp = ast_strdupa(data);
10697 AST_STANDARD_APP_ARGS(args, tmp);
10698 if (args.argc == 2) {
10699 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10700 return -1;
10701 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10702 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10703 int gain;
10704
10705 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10706 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10707 return -1;
10708 } else {
10709 leave_options.record_gain = (signed char) gain;
10710 }
10711 }
10712 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10713 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10714 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10715 }
10716 }
10717 } else {
10718 char temp[256];
10719 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10720 if (res < 0)
10721 return res;
10722 if (ast_strlen_zero(temp))
10723 return 0;
10724 args.argv0 = ast_strdupa(temp);
10725 }
10726
10727 res = leave_voicemail(chan, args.argv0, &leave_options);
10728 if (res == 't') {
10729 ast_play_and_wait(chan, "vm-goodbye");
10730 res = 0;
10731 }
10732
10733 if (res == OPERATOR_EXIT) {
10734 res = 0;
10735 }
10736
10737 if (res == ERROR_LOCK_PATH) {
10738 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10739 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10740 res = 0;
10741 }
10742
10743 return res;
10744 }
10745
10746 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10747 {
10748 struct ast_vm_user *vmu;
10749
10750 if (!ast_strlen_zero(box) && box[0] == '*') {
10751 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10752 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10753 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10754 "\n\tand will be ignored.\n", box, context);
10755 return NULL;
10756 }
10757
10758 AST_LIST_TRAVERSE(&users, vmu, list) {
10759 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10760 if (strcasecmp(vmu->context, context)) {
10761 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10762 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10763 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10764 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10765 }
10766 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10767 return NULL;
10768 }
10769 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10770 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10771 return NULL;
10772 }
10773 }
10774
10775 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10776 return NULL;
10777
10778 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10779 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10780
10781 AST_LIST_INSERT_TAIL(&users, vmu, list);
10782
10783 return vmu;
10784 }
10785
10786 static int append_mailbox(const char *context, const char *box, const char *data)
10787 {
10788
10789 char *tmp;
10790 char *stringp;
10791 char *s;
10792 struct ast_vm_user *vmu;
10793 char *mailbox_full;
10794 int new = 0, old = 0, urgent = 0;
10795 char secretfn[PATH_MAX] = "";
10796
10797 tmp = ast_strdupa(data);
10798
10799 if (!(vmu = find_or_create(context, box)))
10800 return -1;
10801
10802 populate_defaults(vmu);
10803
10804 stringp = tmp;
10805 if ((s = strsep(&stringp, ","))) {
10806 if (!ast_strlen_zero(s) && s[0] == '*') {
10807 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10808 "\n\tmust be reset in voicemail.conf.\n", box);
10809 }
10810
10811 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10812 }
10813 if (stringp && (s = strsep(&stringp, ","))) {
10814 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10815 }
10816 if (stringp && (s = strsep(&stringp, ","))) {
10817 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10818 }
10819 if (stringp && (s = strsep(&stringp, ","))) {
10820 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10821 }
10822 if (stringp && (s = strsep(&stringp, ","))) {
10823 apply_options(vmu, s);
10824 }
10825
10826 switch (vmu->passwordlocation) {
10827 case OPT_PWLOC_SPOOLDIR:
10828 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10829 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10830 }
10831
10832 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
10833 strcpy(mailbox_full, box);
10834 strcat(mailbox_full, "@");
10835 strcat(mailbox_full, context);
10836
10837 inboxcount2(mailbox_full, &urgent, &new, &old);
10838 queue_mwi_event(mailbox_full, urgent, new, old);
10839
10840 return 0;
10841 }
10842
10843 AST_TEST_DEFINE(test_voicemail_vmuser)
10844 {
10845 int res = 0;
10846 struct ast_vm_user *vmu;
10847
10848 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10849 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10850 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10851 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10852 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10853 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10854 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10855 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10856 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10857 #ifdef IMAP_STORAGE
10858 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10859 "imapfolder=INBOX|imapvmshareid=6000";
10860 #endif
10861
10862 switch (cmd) {
10863 case TEST_INIT:
10864 info->name = "vmuser";
10865 info->category = "/apps/app_voicemail/";
10866 info->summary = "Vmuser unit test";
10867 info->description =
10868 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10869 return AST_TEST_NOT_RUN;
10870 case TEST_EXECUTE:
10871 break;
10872 }
10873
10874 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10875 return AST_TEST_NOT_RUN;
10876 }
10877 populate_defaults(vmu);
10878 ast_set_flag(vmu, VM_ALLOCED);
10879
10880 apply_options(vmu, options_string);
10881
10882 if (!ast_test_flag(vmu, VM_ATTACH)) {
10883 ast_test_status_update(test, "Parse failure for attach option\n");
10884 res = 1;
10885 }
10886 if (strcasecmp(vmu->attachfmt, "wav49")) {
10887 ast_test_status_update(test, "Parse failure for attachftm option\n");
10888 res = 1;
10889 }
10890 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10891 ast_test_status_update(test, "Parse failure for serveremail option\n");
10892 res = 1;
10893 }
10894 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10895 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10896 res = 1;
10897 }
10898 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10899 ast_test_status_update(test, "Parse failure for emailbody option\n");
10900 res = 1;
10901 }
10902 if (strcasecmp(vmu->zonetag, "central")) {
10903 ast_test_status_update(test, "Parse failure for tz option\n");
10904 res = 1;
10905 }
10906 if (!ast_test_flag(vmu, VM_DELETE)) {
10907 ast_test_status_update(test, "Parse failure for delete option\n");
10908 res = 1;
10909 }
10910 if (!ast_test_flag(vmu, VM_SAYCID)) {
10911 ast_test_status_update(test, "Parse failure for saycid option\n");
10912 res = 1;
10913 }
10914 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10915 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10916 res = 1;
10917 }
10918 if (!ast_test_flag(vmu, VM_REVIEW)) {
10919 ast_test_status_update(test, "Parse failure for review option\n");
10920 res = 1;
10921 }
10922 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10923 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10924 res = 1;
10925 }
10926 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10927 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10928 res = 1;
10929 }
10930 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10931 ast_test_status_update(test, "Parse failure for operator option\n");
10932 res = 1;
10933 }
10934 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10935 ast_test_status_update(test, "Parse failure for envelope option\n");
10936 res = 1;
10937 }
10938 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10939 ast_test_status_update(test, "Parse failure for moveheard option\n");
10940 res = 1;
10941 }
10942 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10943 ast_test_status_update(test, "Parse failure for sayduration option\n");
10944 res = 1;
10945 }
10946 if (vmu->saydurationm != 5) {
10947 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10948 res = 1;
10949 }
10950 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10951 ast_test_status_update(test, "Parse failure for forcename option\n");
10952 res = 1;
10953 }
10954 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10955 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10956 res = 1;
10957 }
10958 if (strcasecmp(vmu->callback, "somecontext")) {
10959 ast_test_status_update(test, "Parse failure for callbacks option\n");
10960 res = 1;
10961 }
10962 if (strcasecmp(vmu->dialout, "somecontext2")) {
10963 ast_test_status_update(test, "Parse failure for dialout option\n");
10964 res = 1;
10965 }
10966 if (strcasecmp(vmu->exit, "somecontext3")) {
10967 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10968 res = 1;
10969 }
10970 if (vmu->minsecs != 10) {
10971 ast_test_status_update(test, "Parse failure for minsecs option\n");
10972 res = 1;
10973 }
10974 if (vmu->maxsecs != 100) {
10975 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10976 res = 1;
10977 }
10978 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10979 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10980 res = 1;
10981 }
10982 if (vmu->maxdeletedmsg != 50) {
10983 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10984 res = 1;
10985 }
10986 if (vmu->volgain != 1.3) {
10987 ast_test_status_update(test, "Parse failure for volgain option\n");
10988 res = 1;
10989 }
10990 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10991 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10992 res = 1;
10993 }
10994 #ifdef IMAP_STORAGE
10995 apply_options(vmu, option_string2);
10996
10997 if (strcasecmp(vmu->imapuser, "imapuser")) {
10998 ast_test_status_update(test, "Parse failure for imapuser option\n");
10999 res = 1;
11000 }
11001 if (strcasecmp(vmu->imappassword, "imappasswd")) {
11002 ast_test_status_update(test, "Parse failure for imappasswd option\n");
11003 res = 1;
11004 }
11005 if (strcasecmp(vmu->imapfolder, "INBOX")) {
11006 ast_test_status_update(test, "Parse failure for imapfolder option\n");
11007 res = 1;
11008 }
11009 if (strcasecmp(vmu->imapvmshareid, "6000")) {
11010 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
11011 res = 1;
11012 }
11013 #endif
11014
11015 free_user(vmu);
11016 return res ? AST_TEST_FAIL : AST_TEST_PASS;
11017 }
11018
11019 static int vm_box_exists(struct ast_channel *chan, const char *data)
11020 {
11021 struct ast_vm_user svm;
11022 char *context, *box;
11023 AST_DECLARE_APP_ARGS(args,
11024 AST_APP_ARG(mbox);
11025 AST_APP_ARG(options);
11026 );
11027 static int dep_warning = 0;
11028
11029 if (ast_strlen_zero(data)) {
11030 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
11031 return -1;
11032 }
11033
11034 if (!dep_warning) {
11035 dep_warning = 1;
11036 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
11037 }
11038
11039 box = ast_strdupa(data);
11040
11041 AST_STANDARD_APP_ARGS(args, box);
11042
11043 if (args.options) {
11044 }
11045
11046 if ((context = strchr(args.mbox, '@'))) {
11047 *context = '\0';
11048 context++;
11049 }
11050
11051 if (find_user(&svm, context, args.mbox)) {
11052 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11053 } else
11054 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11055
11056 return 0;
11057 }
11058
11059 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11060 {
11061 struct ast_vm_user svm;
11062 AST_DECLARE_APP_ARGS(arg,
11063 AST_APP_ARG(mbox);
11064 AST_APP_ARG(context);
11065 );
11066
11067 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11068
11069 if (ast_strlen_zero(arg.mbox)) {
11070 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11071 return -1;
11072 }
11073
11074 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11075 return 0;
11076 }
11077
11078 static struct ast_custom_function mailbox_exists_acf = {
11079 .name = "MAILBOX_EXISTS",
11080 .read = acf_mailbox_exists,
11081 };
11082
11083 static int vmauthenticate(struct ast_channel *chan, const char *data)
11084 {
11085 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11086 struct ast_vm_user vmus;
11087 char *options = NULL;
11088 int silent = 0, skipuser = 0;
11089 int res = -1;
11090
11091 if (data) {
11092 s = ast_strdupa(data);
11093 user = strsep(&s, ",");
11094 options = strsep(&s, ",");
11095 if (user) {
11096 s = user;
11097 user = strsep(&s, "@");
11098 context = strsep(&s, "");
11099 if (!ast_strlen_zero(user))
11100 skipuser++;
11101 ast_copy_string(mailbox, user, sizeof(mailbox));
11102 }
11103 }
11104
11105 if (options) {
11106 silent = (strchr(options, 's')) != NULL;
11107 }
11108
11109 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11110 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11111 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11112 ast_play_and_wait(chan, "auth-thankyou");
11113 res = 0;
11114 } else if (mailbox[0] == '*') {
11115
11116 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11117 res = 0;
11118 }
11119 }
11120
11121 return res;
11122 }
11123
11124 static char *show_users_realtime(int fd, const char *context)
11125 {
11126 struct ast_config *cfg;
11127 const char *cat = NULL;
11128
11129 if (!(cfg = ast_load_realtime_multientry("voicemail",
11130 "context", context, SENTINEL))) {
11131 return CLI_FAILURE;
11132 }
11133
11134 ast_cli(fd,
11135 "\n"
11136 "=============================================================\n"
11137 "=== Configured Voicemail Users ==============================\n"
11138 "=============================================================\n"
11139 "===\n");
11140
11141 while ((cat = ast_category_browse(cfg, cat))) {
11142 struct ast_variable *var = NULL;
11143 ast_cli(fd,
11144 "=== Mailbox ...\n"
11145 "===\n");
11146 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11147 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11148 ast_cli(fd,
11149 "===\n"
11150 "=== ---------------------------------------------------------\n"
11151 "===\n");
11152 }
11153
11154 ast_cli(fd,
11155 "=============================================================\n"
11156 "\n");
11157
11158 ast_config_destroy(cfg);
11159
11160 return CLI_SUCCESS;
11161 }
11162
11163 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11164 {
11165 int which = 0;
11166 int wordlen;
11167 struct ast_vm_user *vmu;
11168 const char *context = "";
11169
11170
11171 if (pos > 4)
11172 return NULL;
11173 if (pos == 3)
11174 return (state == 0) ? ast_strdup("for") : NULL;
11175 wordlen = strlen(word);
11176 AST_LIST_TRAVERSE(&users, vmu, list) {
11177 if (!strncasecmp(word, vmu->context, wordlen)) {
11178 if (context && strcmp(context, vmu->context) && ++which > state)
11179 return ast_strdup(vmu->context);
11180
11181 context = vmu->context;
11182 }
11183 }
11184 return NULL;
11185 }
11186
11187
11188 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11189 {
11190 struct ast_vm_user *vmu;
11191 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11192 const char *context = NULL;
11193 int users_counter = 0;
11194
11195 switch (cmd) {
11196 case CLI_INIT:
11197 e->command = "voicemail show users";
11198 e->usage =
11199 "Usage: voicemail show users [for <context>]\n"
11200 " Lists all mailboxes currently set up\n";
11201 return NULL;
11202 case CLI_GENERATE:
11203 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11204 }
11205
11206 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11207 return CLI_SHOWUSAGE;
11208 if (a->argc == 5) {
11209 if (strcmp(a->argv[3],"for"))
11210 return CLI_SHOWUSAGE;
11211 context = a->argv[4];
11212 }
11213
11214 if (ast_check_realtime("voicemail")) {
11215 if (!context) {
11216 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11217 return CLI_SHOWUSAGE;
11218 }
11219 return show_users_realtime(a->fd, context);
11220 }
11221
11222 AST_LIST_LOCK(&users);
11223 if (AST_LIST_EMPTY(&users)) {
11224 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11225 AST_LIST_UNLOCK(&users);
11226 return CLI_FAILURE;
11227 }
11228 if (!context) {
11229 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11230 } else {
11231 int count = 0;
11232 AST_LIST_TRAVERSE(&users, vmu, list) {
11233 if (!strcmp(context, vmu->context)) {
11234 count++;
11235 break;
11236 }
11237 }
11238 if (count) {
11239 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11240 } else {
11241 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11242 AST_LIST_UNLOCK(&users);
11243 return CLI_FAILURE;
11244 }
11245 }
11246 AST_LIST_TRAVERSE(&users, vmu, list) {
11247 int newmsgs = 0, oldmsgs = 0;
11248 char count[12], tmp[256] = "";
11249
11250 if (!context || !strcmp(context, vmu->context)) {
11251 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11252 inboxcount(tmp, &newmsgs, &oldmsgs);
11253 snprintf(count, sizeof(count), "%d", newmsgs);
11254 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11255 users_counter++;
11256 }
11257 }
11258 AST_LIST_UNLOCK(&users);
11259 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11260 return CLI_SUCCESS;
11261 }
11262
11263
11264 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11265 {
11266 struct vm_zone *zone;
11267 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11268 char *res = CLI_SUCCESS;
11269
11270 switch (cmd) {
11271 case CLI_INIT:
11272 e->command = "voicemail show zones";
11273 e->usage =
11274 "Usage: voicemail show zones\n"
11275 " Lists zone message formats\n";
11276 return NULL;
11277 case CLI_GENERATE:
11278 return NULL;
11279 }
11280
11281 if (a->argc != 3)
11282 return CLI_SHOWUSAGE;
11283
11284 AST_LIST_LOCK(&zones);
11285 if (!AST_LIST_EMPTY(&zones)) {
11286 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11287 AST_LIST_TRAVERSE(&zones, zone, list) {
11288 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11289 }
11290 } else {
11291 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11292 res = CLI_FAILURE;
11293 }
11294 AST_LIST_UNLOCK(&zones);
11295
11296 return res;
11297 }
11298
11299
11300 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11301 {
11302 switch (cmd) {
11303 case CLI_INIT:
11304 e->command = "voicemail reload";
11305 e->usage =
11306 "Usage: voicemail reload\n"
11307 " Reload voicemail configuration\n";
11308 return NULL;
11309 case CLI_GENERATE:
11310 return NULL;
11311 }
11312
11313 if (a->argc != 2)
11314 return CLI_SHOWUSAGE;
11315
11316 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11317 load_config(1);
11318
11319 return CLI_SUCCESS;
11320 }
11321
11322 static struct ast_cli_entry cli_voicemail[] = {
11323 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11324 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11325 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11326 };
11327
11328 #ifdef IMAP_STORAGE
11329 #define DATA_EXPORT_VM_USERS(USER) \
11330 USER(ast_vm_user, context, AST_DATA_STRING) \
11331 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11332 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11333 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11334 USER(ast_vm_user, email, AST_DATA_STRING) \
11335 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11336 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11337 USER(ast_vm_user, pager, AST_DATA_STRING) \
11338 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11339 USER(ast_vm_user, language, AST_DATA_STRING) \
11340 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11341 USER(ast_vm_user, callback, AST_DATA_STRING) \
11342 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11343 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11344 USER(ast_vm_user, exit, AST_DATA_STRING) \
11345 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11346 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11347 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11348 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11349 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11350 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11351 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11352 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11353 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11354 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11355 #else
11356 #define DATA_EXPORT_VM_USERS(USER) \
11357 USER(ast_vm_user, context, AST_DATA_STRING) \
11358 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11359 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11360 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11361 USER(ast_vm_user, email, AST_DATA_STRING) \
11362 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11363 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11364 USER(ast_vm_user, pager, AST_DATA_STRING) \
11365 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11366 USER(ast_vm_user, language, AST_DATA_STRING) \
11367 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11368 USER(ast_vm_user, callback, AST_DATA_STRING) \
11369 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11370 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11371 USER(ast_vm_user, exit, AST_DATA_STRING) \
11372 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11373 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11374 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11375 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11376 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11377 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11378 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11379 #endif
11380
11381 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11382
11383 #define DATA_EXPORT_VM_ZONES(ZONE) \
11384 ZONE(vm_zone, name, AST_DATA_STRING) \
11385 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11386 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11387
11388 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11389
11390
11391
11392
11393
11394
11395
11396
11397 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11398 struct ast_data *data_root, struct ast_vm_user *user)
11399 {
11400 struct ast_data *data_user, *data_zone;
11401 struct ast_data *data_state;
11402 struct vm_zone *zone = NULL;
11403 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11404 char ext_context[256] = "";
11405
11406 data_user = ast_data_add_node(data_root, "user");
11407 if (!data_user) {
11408 return -1;
11409 }
11410
11411 ast_data_add_structure(ast_vm_user, data_user, user);
11412
11413 AST_LIST_LOCK(&zones);
11414 AST_LIST_TRAVERSE(&zones, zone, list) {
11415 if (!strcmp(zone->name, user->zonetag)) {
11416 break;
11417 }
11418 }
11419 AST_LIST_UNLOCK(&zones);
11420
11421
11422 data_state = ast_data_add_node(data_user, "state");
11423 if (!data_state) {
11424 return -1;
11425 }
11426 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11427 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11428 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11429 ast_data_add_int(data_state, "newmsg", newmsg);
11430 ast_data_add_int(data_state, "oldmsg", oldmsg);
11431
11432 if (zone) {
11433 data_zone = ast_data_add_node(data_user, "zone");
11434 ast_data_add_structure(vm_zone, data_zone, zone);
11435 }
11436
11437 if (!ast_data_search_match(search, data_user)) {
11438 ast_data_remove_node(data_root, data_user);
11439 }
11440
11441 return 0;
11442 }
11443
11444 static int vm_users_data_provider_get(const struct ast_data_search *search,
11445 struct ast_data *data_root)
11446 {
11447 struct ast_vm_user *user;
11448
11449 AST_LIST_LOCK(&users);
11450 AST_LIST_TRAVERSE(&users, user, list) {
11451 vm_users_data_provider_get_helper(search, data_root, user);
11452 }
11453 AST_LIST_UNLOCK(&users);
11454
11455 return 0;
11456 }
11457
11458 static const struct ast_data_handler vm_users_data_provider = {
11459 .version = AST_DATA_HANDLER_VERSION,
11460 .get = vm_users_data_provider_get
11461 };
11462
11463 static const struct ast_data_entry vm_data_providers[] = {
11464 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11465 };
11466
11467 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11468 {
11469 int new = 0, old = 0, urgent = 0;
11470
11471 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11472
11473 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11474 mwi_sub->old_urgent = urgent;
11475 mwi_sub->old_new = new;
11476 mwi_sub->old_old = old;
11477 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11478 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11479 }
11480 }
11481
11482 static void poll_subscribed_mailboxes(void)
11483 {
11484 struct mwi_sub *mwi_sub;
11485
11486 AST_RWLIST_RDLOCK(&mwi_subs);
11487 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11488 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11489 poll_subscribed_mailbox(mwi_sub);
11490 }
11491 }
11492 AST_RWLIST_UNLOCK(&mwi_subs);
11493 }
11494
11495 static void *mb_poll_thread(void *data)
11496 {
11497 while (poll_thread_run) {
11498 struct timespec ts = { 0, };
11499 struct timeval wait;
11500
11501 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11502 ts.tv_sec = wait.tv_sec;
11503 ts.tv_nsec = wait.tv_usec * 1000;
11504
11505 ast_mutex_lock(&poll_lock);
11506 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11507 ast_mutex_unlock(&poll_lock);
11508
11509 if (!poll_thread_run)
11510 break;
11511
11512 poll_subscribed_mailboxes();
11513 }
11514
11515 return NULL;
11516 }
11517
11518 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11519 {
11520 ast_free(mwi_sub);
11521 }
11522
11523 static int handle_unsubscribe(void *datap)
11524 {
11525 struct mwi_sub *mwi_sub;
11526 uint32_t *uniqueid = datap;
11527
11528 AST_RWLIST_WRLOCK(&mwi_subs);
11529 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11530 if (mwi_sub->uniqueid == *uniqueid) {
11531 AST_LIST_REMOVE_CURRENT(entry);
11532 break;
11533 }
11534 }
11535 AST_RWLIST_TRAVERSE_SAFE_END
11536 AST_RWLIST_UNLOCK(&mwi_subs);
11537
11538 if (mwi_sub)
11539 mwi_sub_destroy(mwi_sub);
11540
11541 ast_free(uniqueid);
11542 return 0;
11543 }
11544
11545 static int handle_subscribe(void *datap)
11546 {
11547 unsigned int len;
11548 struct mwi_sub *mwi_sub;
11549 struct mwi_sub_task *p = datap;
11550
11551 len = sizeof(*mwi_sub);
11552 if (!ast_strlen_zero(p->mailbox))
11553 len += strlen(p->mailbox);
11554
11555 if (!ast_strlen_zero(p->context))
11556 len += strlen(p->context) + 1;
11557
11558 if (!(mwi_sub = ast_calloc(1, len)))
11559 return -1;
11560
11561 mwi_sub->uniqueid = p->uniqueid;
11562 if (!ast_strlen_zero(p->mailbox))
11563 strcpy(mwi_sub->mailbox, p->mailbox);
11564
11565 if (!ast_strlen_zero(p->context)) {
11566 strcat(mwi_sub->mailbox, "@");
11567 strcat(mwi_sub->mailbox, p->context);
11568 }
11569
11570 AST_RWLIST_WRLOCK(&mwi_subs);
11571 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11572 AST_RWLIST_UNLOCK(&mwi_subs);
11573 ast_free((void *) p->mailbox);
11574 ast_free((void *) p->context);
11575 ast_free(p);
11576 poll_subscribed_mailbox(mwi_sub);
11577 return 0;
11578 }
11579
11580 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11581 {
11582 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11583
11584 if (!uniqueid) {
11585 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11586 return;
11587 }
11588
11589 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11590 ast_free(uniqueid);
11591 return;
11592 }
11593
11594 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11595 ast_free(uniqueid);
11596 return;
11597 }
11598
11599 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11600 *uniqueid = u;
11601 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11602 ast_free(uniqueid);
11603 }
11604 }
11605
11606 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11607 {
11608 struct mwi_sub_task *mwist;
11609
11610 if (ast_event_get_type(event) != AST_EVENT_SUB)
11611 return;
11612
11613 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11614 return;
11615
11616 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11617 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11618 return;
11619 }
11620 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11621 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11622 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11623
11624 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11625 ast_free(mwist);
11626 }
11627 }
11628
11629 static void start_poll_thread(void)
11630 {
11631 int errcode;
11632 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11633 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11634 AST_EVENT_IE_END);
11635
11636 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11637 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11638 AST_EVENT_IE_END);
11639
11640 if (mwi_sub_sub)
11641 ast_event_report_subs(mwi_sub_sub);
11642
11643 poll_thread_run = 1;
11644
11645 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11646 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11647 }
11648 }
11649
11650 static void stop_poll_thread(void)
11651 {
11652 poll_thread_run = 0;
11653
11654 if (mwi_sub_sub) {
11655 ast_event_unsubscribe(mwi_sub_sub);
11656 mwi_sub_sub = NULL;
11657 }
11658
11659 if (mwi_unsub_sub) {
11660 ast_event_unsubscribe(mwi_unsub_sub);
11661 mwi_unsub_sub = NULL;
11662 }
11663
11664 ast_mutex_lock(&poll_lock);
11665 ast_cond_signal(&poll_cond);
11666 ast_mutex_unlock(&poll_lock);
11667
11668 pthread_join(poll_thread, NULL);
11669
11670 poll_thread = AST_PTHREADT_NULL;
11671 }
11672
11673
11674 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11675 {
11676 struct ast_vm_user *vmu = NULL;
11677 const char *id = astman_get_header(m, "ActionID");
11678 char actionid[128] = "";
11679
11680 if (!ast_strlen_zero(id))
11681 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11682
11683 AST_LIST_LOCK(&users);
11684
11685 if (AST_LIST_EMPTY(&users)) {
11686 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11687 AST_LIST_UNLOCK(&users);
11688 return RESULT_SUCCESS;
11689 }
11690
11691 astman_send_ack(s, m, "Voicemail user list will follow");
11692
11693 AST_LIST_TRAVERSE(&users, vmu, list) {
11694 char dirname[256];
11695
11696 #ifdef IMAP_STORAGE
11697 int new, old;
11698 inboxcount(vmu->mailbox, &new, &old);
11699 #endif
11700
11701 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11702 astman_append(s,
11703 "%s"
11704 "Event: VoicemailUserEntry\r\n"
11705 "VMContext: %s\r\n"
11706 "VoiceMailbox: %s\r\n"
11707 "Fullname: %s\r\n"
11708 "Email: %s\r\n"
11709 "Pager: %s\r\n"
11710 "ServerEmail: %s\r\n"
11711 "MailCommand: %s\r\n"
11712 "Language: %s\r\n"
11713 "TimeZone: %s\r\n"
11714 "Callback: %s\r\n"
11715 "Dialout: %s\r\n"
11716 "UniqueID: %s\r\n"
11717 "ExitContext: %s\r\n"
11718 "SayDurationMinimum: %d\r\n"
11719 "SayEnvelope: %s\r\n"
11720 "SayCID: %s\r\n"
11721 "AttachMessage: %s\r\n"
11722 "AttachmentFormat: %s\r\n"
11723 "DeleteMessage: %s\r\n"
11724 "VolumeGain: %.2f\r\n"
11725 "CanReview: %s\r\n"
11726 "CallOperator: %s\r\n"
11727 "MaxMessageCount: %d\r\n"
11728 "MaxMessageLength: %d\r\n"
11729 "NewMessageCount: %d\r\n"
11730 #ifdef IMAP_STORAGE
11731 "OldMessageCount: %d\r\n"
11732 "IMAPUser: %s\r\n"
11733 #endif
11734 "\r\n",
11735 actionid,
11736 vmu->context,
11737 vmu->mailbox,
11738 vmu->fullname,
11739 vmu->email,
11740 vmu->pager,
11741 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
11742 mailcmd,
11743 vmu->language,
11744 vmu->zonetag,
11745 vmu->callback,
11746 vmu->dialout,
11747 vmu->uniqueid,
11748 vmu->exit,
11749 vmu->saydurationm,
11750 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11751 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11752 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11753 vmu->attachfmt,
11754 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11755 vmu->volgain,
11756 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11757 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11758 vmu->maxmsg,
11759 vmu->maxsecs,
11760 #ifdef IMAP_STORAGE
11761 new, old, vmu->imapuser
11762 #else
11763 count_messages(vmu, dirname)
11764 #endif
11765 );
11766 }
11767 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11768
11769 AST_LIST_UNLOCK(&users);
11770
11771 return RESULT_SUCCESS;
11772 }
11773
11774
11775 static void free_vm_users(void)
11776 {
11777 struct ast_vm_user *current;
11778 AST_LIST_LOCK(&users);
11779 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11780 ast_set_flag(current, VM_ALLOCED);
11781 free_user(current);
11782 }
11783 AST_LIST_UNLOCK(&users);
11784 }
11785
11786
11787 static void free_vm_zones(void)
11788 {
11789 struct vm_zone *zcur;
11790 AST_LIST_LOCK(&zones);
11791 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11792 free_zone(zcur);
11793 AST_LIST_UNLOCK(&zones);
11794 }
11795
11796 static const char *substitute_escapes(const char *value)
11797 {
11798 char *current;
11799
11800
11801 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11802
11803 ast_str_reset(str);
11804
11805
11806 for (current = (char *) value; *current; current++) {
11807 if (*current == '\\') {
11808 current++;
11809 if (!*current) {
11810 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11811 break;
11812 }
11813 switch (*current) {
11814 case '\\':
11815 ast_str_append(&str, 0, "\\");
11816 break;
11817 case 'r':
11818 ast_str_append(&str, 0, "\r");
11819 break;
11820 case 'n':
11821 #ifdef IMAP_STORAGE
11822 if (!str->used || str->str[str->used - 1] != '\r') {
11823 ast_str_append(&str, 0, "\r");
11824 }
11825 #endif
11826 ast_str_append(&str, 0, "\n");
11827 break;
11828 case 't':
11829 ast_str_append(&str, 0, "\t");
11830 break;
11831 default:
11832 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11833 break;
11834 }
11835 } else {
11836 ast_str_append(&str, 0, "%c", *current);
11837 }
11838 }
11839
11840 return ast_str_buffer(str);
11841 }
11842
11843 static int load_config(int reload)
11844 {
11845 struct ast_config *cfg, *ucfg;
11846 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11847 int res;
11848
11849 ast_unload_realtime("voicemail");
11850 ast_unload_realtime("voicemail_data");
11851
11852 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11853 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11854 return 0;
11855 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11856 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11857 ucfg = NULL;
11858 }
11859 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11860 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11861 ast_config_destroy(ucfg);
11862 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11863 return 0;
11864 }
11865 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11866 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11867 return 0;
11868 } else {
11869 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11870 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11871 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11872 ucfg = NULL;
11873 }
11874 }
11875
11876 res = actual_load_config(reload, cfg, ucfg);
11877
11878 ast_config_destroy(cfg);
11879 ast_config_destroy(ucfg);
11880
11881 return res;
11882 }
11883
11884 #ifdef TEST_FRAMEWORK
11885 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11886 {
11887 ast_unload_realtime("voicemail");
11888 ast_unload_realtime("voicemail_data");
11889 return actual_load_config(reload, cfg, ucfg);
11890 }
11891 #endif
11892
11893 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11894 {
11895 struct ast_vm_user *current;
11896 char *cat;
11897 struct ast_variable *var;
11898 const char *val;
11899 char *q, *stringp, *tmp;
11900 int x;
11901 unsigned int tmpadsi[4];
11902 char secretfn[PATH_MAX] = "";
11903
11904 #ifdef IMAP_STORAGE
11905 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11906 #endif
11907
11908 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11909 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11910 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11911 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11912 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11913
11914
11915 free_vm_users();
11916
11917
11918 free_vm_zones();
11919
11920 AST_LIST_LOCK(&users);
11921
11922 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11923 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11924
11925 if (cfg) {
11926
11927
11928 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11929 val = "default";
11930 ast_copy_string(userscontext, val, sizeof(userscontext));
11931
11932 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11933 val = "yes";
11934 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11935
11936 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11937 val = "no";
11938 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11939
11940 volgain = 0.0;
11941 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11942 sscanf(val, "%30lf", &volgain);
11943
11944 #ifdef ODBC_STORAGE
11945 strcpy(odbc_database, "asterisk");
11946 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11947 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11948 }
11949 strcpy(odbc_table, "voicemessages");
11950 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11951 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11952 }
11953 #endif
11954
11955 strcpy(mailcmd, SENDMAIL);
11956 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11957 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11958
11959 maxsilence = 0;
11960 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11961 maxsilence = atoi(val);
11962 if (maxsilence > 0)
11963 maxsilence *= 1000;
11964 }
11965
11966 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11967 maxmsg = MAXMSG;
11968 } else {
11969 maxmsg = atoi(val);
11970 if (maxmsg < 0) {
11971 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11972 maxmsg = MAXMSG;
11973 } else if (maxmsg > MAXMSGLIMIT) {
11974 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11975 maxmsg = MAXMSGLIMIT;
11976 }
11977 }
11978
11979 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11980 maxdeletedmsg = 0;
11981 } else {
11982 if (sscanf(val, "%30d", &x) == 1)
11983 maxdeletedmsg = x;
11984 else if (ast_true(val))
11985 maxdeletedmsg = MAXMSG;
11986 else
11987 maxdeletedmsg = 0;
11988
11989 if (maxdeletedmsg < 0) {
11990 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11991 maxdeletedmsg = MAXMSG;
11992 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11993 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11994 maxdeletedmsg = MAXMSGLIMIT;
11995 }
11996 }
11997
11998
11999 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
12000 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
12001 }
12002
12003
12004 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
12005 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
12006 }
12007
12008
12009 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
12010 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12011 pwdchange = PWDCHANGE_EXTERNAL;
12012 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
12013 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12014 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
12015 }
12016
12017
12018 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
12019 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
12020 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
12021 }
12022
12023 #ifdef IMAP_STORAGE
12024
12025 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
12026 ast_copy_string(imapserver, val, sizeof(imapserver));
12027 } else {
12028 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
12029 }
12030
12031 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
12032 ast_copy_string(imapport, val, sizeof(imapport));
12033 } else {
12034 ast_copy_string(imapport, "143", sizeof(imapport));
12035 }
12036
12037 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
12038 ast_copy_string(imapflags, val, sizeof(imapflags));
12039 }
12040
12041 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12042 ast_copy_string(authuser, val, sizeof(authuser));
12043 }
12044
12045 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12046 ast_copy_string(authpassword, val, sizeof(authpassword));
12047 }
12048
12049 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12050 if (ast_false(val))
12051 expungeonhangup = 0;
12052 else
12053 expungeonhangup = 1;
12054 } else {
12055 expungeonhangup = 1;
12056 }
12057
12058 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12059 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12060 } else {
12061 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12062 }
12063 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12064 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12065 }
12066 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12067 imapgreetings = ast_true(val);
12068 } else {
12069 imapgreetings = 0;
12070 }
12071 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12072 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12073 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12074
12075 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12076 } else {
12077 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12078 }
12079
12080
12081
12082
12083
12084 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12085 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12086 } else {
12087 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12088 }
12089
12090 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12091 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12092 } else {
12093 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12094 }
12095
12096 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12097 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12098 } else {
12099 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12100 }
12101
12102 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12103 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12104 } else {
12105 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12106 }
12107
12108
12109 imapversion++;
12110 #endif
12111
12112 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12113 ast_copy_string(externnotify, val, sizeof(externnotify));
12114 ast_debug(1, "found externnotify: %s\n", externnotify);
12115 } else {
12116 externnotify[0] = '\0';
12117 }
12118
12119
12120 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12121 ast_debug(1, "Enabled SMDI voicemail notification\n");
12122 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12123 smdi_iface = ast_smdi_interface_find(val);
12124 } else {
12125 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12126 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12127 }
12128 if (!smdi_iface) {
12129 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12130 }
12131 }
12132
12133
12134 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12135 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12136 silencethreshold = atoi(val);
12137
12138 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12139 val = ASTERISK_USERNAME;
12140 ast_copy_string(serveremail, val, sizeof(serveremail));
12141
12142 vmmaxsecs = 0;
12143 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12144 if (sscanf(val, "%30d", &x) == 1) {
12145 vmmaxsecs = x;
12146 } else {
12147 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12148 }
12149 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12150 static int maxmessage_deprecate = 0;
12151 if (maxmessage_deprecate == 0) {
12152 maxmessage_deprecate = 1;
12153 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12154 }
12155 if (sscanf(val, "%30d", &x) == 1) {
12156 vmmaxsecs = x;
12157 } else {
12158 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12159 }
12160 }
12161
12162 vmminsecs = 0;
12163 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12164 if (sscanf(val, "%30d", &x) == 1) {
12165 vmminsecs = x;
12166 if (maxsilence / 1000 >= vmminsecs) {
12167 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12168 }
12169 } else {
12170 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12171 }
12172 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12173 static int maxmessage_deprecate = 0;
12174 if (maxmessage_deprecate == 0) {
12175 maxmessage_deprecate = 1;
12176 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12177 }
12178 if (sscanf(val, "%30d", &x) == 1) {
12179 vmminsecs = x;
12180 if (maxsilence / 1000 >= vmminsecs) {
12181 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12182 }
12183 } else {
12184 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12185 }
12186 }
12187
12188 val = ast_variable_retrieve(cfg, "general", "format");
12189 if (!val) {
12190 val = "wav";
12191 } else {
12192 tmp = ast_strdupa(val);
12193 val = ast_format_str_reduce(tmp);
12194 if (!val) {
12195 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12196 val = "wav";
12197 }
12198 }
12199 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12200
12201 skipms = 3000;
12202 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12203 if (sscanf(val, "%30d", &x) == 1) {
12204 maxgreet = x;
12205 } else {
12206 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12207 }
12208 }
12209
12210 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12211 if (sscanf(val, "%30d", &x) == 1) {
12212 skipms = x;
12213 } else {
12214 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12215 }
12216 }
12217
12218 maxlogins = 3;
12219 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12220 if (sscanf(val, "%30d", &x) == 1) {
12221 maxlogins = x;
12222 } else {
12223 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12224 }
12225 }
12226
12227 minpassword = MINPASSWORD;
12228 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12229 if (sscanf(val, "%30d", &x) == 1) {
12230 minpassword = x;
12231 } else {
12232 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12233 }
12234 }
12235
12236
12237 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12238 val = "no";
12239 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12240
12241
12242 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12243 val = "no";
12244 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12245
12246 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12247 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12248 stringp = ast_strdupa(val);
12249 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12250 if (!ast_strlen_zero(stringp)) {
12251 q = strsep(&stringp, ",");
12252 while ((*q == ' ')||(*q == '\t'))
12253 q++;
12254 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12255 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12256 } else {
12257 cidinternalcontexts[x][0] = '\0';
12258 }
12259 }
12260 }
12261 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12262 ast_debug(1, "VM Review Option disabled globally\n");
12263 val = "no";
12264 }
12265 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12266
12267
12268 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12269 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12270 val = "no";
12271 } else {
12272 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12273 }
12274 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12275 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12276 ast_debug(1, "VM next message wrap disabled globally\n");
12277 val = "no";
12278 }
12279 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12280
12281 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12282 ast_debug(1, "VM Operator break disabled globally\n");
12283 val = "no";
12284 }
12285 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12286
12287 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12288 ast_debug(1, "VM CID Info before msg disabled globally\n");
12289 val = "no";
12290 }
12291 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12292
12293 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12294 ast_debug(1, "Send Voicemail msg disabled globally\n");
12295 val = "no";
12296 }
12297 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12298
12299 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12300 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12301 val = "yes";
12302 }
12303 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12304
12305 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12306 ast_debug(1, "Move Heard enabled globally\n");
12307 val = "yes";
12308 }
12309 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12310
12311 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12312 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12313 val = "no";
12314 }
12315 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12316
12317 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12318 ast_debug(1, "Duration info before msg enabled globally\n");
12319 val = "yes";
12320 }
12321 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12322
12323 saydurationminfo = 2;
12324 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12325 if (sscanf(val, "%30d", &x) == 1) {
12326 saydurationminfo = x;
12327 } else {
12328 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12329 }
12330 }
12331
12332 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12333 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12334 val = "no";
12335 }
12336 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12337
12338 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12339 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12340 ast_debug(1, "found dialout context: %s\n", dialcontext);
12341 } else {
12342 dialcontext[0] = '\0';
12343 }
12344
12345 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12346 ast_copy_string(callcontext, val, sizeof(callcontext));
12347 ast_debug(1, "found callback context: %s\n", callcontext);
12348 } else {
12349 callcontext[0] = '\0';
12350 }
12351
12352 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12353 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12354 ast_debug(1, "found operator context: %s\n", exitcontext);
12355 } else {
12356 exitcontext[0] = '\0';
12357 }
12358
12359
12360 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12361 ast_copy_string(vm_password, val, sizeof(vm_password));
12362 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12363 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12364 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12365 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12366 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12367 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12368 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12369 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12370 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12371 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12372 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12373 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12374 }
12375 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12376 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12377 }
12378
12379 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12380 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12381 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12382 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12383 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12384 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12385 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12386 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12387 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12388 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12389
12390 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12391 val = "no";
12392 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12393
12394 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12395 val = "voicemail.conf";
12396 }
12397 if (!(strcmp(val, "spooldir"))) {
12398 passwordlocation = OPT_PWLOC_SPOOLDIR;
12399 } else {
12400 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12401 }
12402
12403 poll_freq = DEFAULT_POLL_FREQ;
12404 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12405 if (sscanf(val, "%30u", &poll_freq) != 1) {
12406 poll_freq = DEFAULT_POLL_FREQ;
12407 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12408 }
12409 }
12410
12411 poll_mailboxes = 0;
12412 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12413 poll_mailboxes = ast_true(val);
12414
12415 memset(fromstring, 0, sizeof(fromstring));
12416 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12417 strcpy(charset, "ISO-8859-1");
12418 if (emailbody) {
12419 ast_free(emailbody);
12420 emailbody = NULL;
12421 }
12422 if (emailsubject) {
12423 ast_free(emailsubject);
12424 emailsubject = NULL;
12425 }
12426 if (pagerbody) {
12427 ast_free(pagerbody);
12428 pagerbody = NULL;
12429 }
12430 if (pagersubject) {
12431 ast_free(pagersubject);
12432 pagersubject = NULL;
12433 }
12434 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12435 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12436 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12437 ast_copy_string(fromstring, val, sizeof(fromstring));
12438 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12439 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12440 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12441 ast_copy_string(charset, val, sizeof(charset));
12442 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12443 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12444 for (x = 0; x < 4; x++) {
12445 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12446 }
12447 }
12448 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12449 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12450 for (x = 0; x < 4; x++) {
12451 memcpy(&adsisec[x], &tmpadsi[x], 1);
12452 }
12453 }
12454 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12455 if (atoi(val)) {
12456 adsiver = atoi(val);
12457 }
12458 }
12459 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12460 ast_copy_string(zonetag, val, sizeof(zonetag));
12461 }
12462 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12463 ast_copy_string(locale, val, sizeof(locale));
12464 }
12465 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12466 emailsubject = ast_strdup(substitute_escapes(val));
12467 }
12468 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12469 emailbody = ast_strdup(substitute_escapes(val));
12470 }
12471 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12472 pagersubject = ast_strdup(substitute_escapes(val));
12473 }
12474 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12475 pagerbody = ast_strdup(substitute_escapes(val));
12476 }
12477
12478
12479 if (ucfg) {
12480 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12481 if (!strcasecmp(cat, "general")) {
12482 continue;
12483 }
12484 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12485 continue;
12486 if ((current = find_or_create(userscontext, cat))) {
12487 populate_defaults(current);
12488 apply_options_full(current, ast_variable_browse(ucfg, cat));
12489 ast_copy_string(current->context, userscontext, sizeof(current->context));
12490 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12491 current->passwordlocation = OPT_PWLOC_USERSCONF;
12492 }
12493
12494 switch (current->passwordlocation) {
12495 case OPT_PWLOC_SPOOLDIR:
12496 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12497 read_password_from_file(secretfn, current->password, sizeof(current->password));
12498 }
12499 }
12500 }
12501 }
12502
12503
12504 cat = ast_category_browse(cfg, NULL);
12505 while (cat) {
12506 if (strcasecmp(cat, "general")) {
12507 var = ast_variable_browse(cfg, cat);
12508 if (strcasecmp(cat, "zonemessages")) {
12509
12510 while (var) {
12511 append_mailbox(cat, var->name, var->value);
12512 var = var->next;
12513 }
12514 } else {
12515
12516 while (var) {
12517 struct vm_zone *z;
12518 if ((z = ast_malloc(sizeof(*z)))) {
12519 char *msg_format, *tzone;
12520 msg_format = ast_strdupa(var->value);
12521 tzone = strsep(&msg_format, "|,");
12522 if (msg_format) {
12523 ast_copy_string(z->name, var->name, sizeof(z->name));
12524 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12525 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12526 AST_LIST_LOCK(&zones);
12527 AST_LIST_INSERT_HEAD(&zones, z, list);
12528 AST_LIST_UNLOCK(&zones);
12529 } else {
12530 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12531 ast_free(z);
12532 }
12533 } else {
12534 AST_LIST_UNLOCK(&users);
12535 return -1;
12536 }
12537 var = var->next;
12538 }
12539 }
12540 }
12541 cat = ast_category_browse(cfg, cat);
12542 }
12543
12544 AST_LIST_UNLOCK(&users);
12545
12546 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12547 start_poll_thread();
12548 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12549 stop_poll_thread();;
12550
12551 return 0;
12552 } else {
12553 AST_LIST_UNLOCK(&users);
12554 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12555 return 0;
12556 }
12557 }
12558
12559 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12560 {
12561 int res = -1;
12562 char dir[PATH_MAX];
12563 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12564 ast_debug(2, "About to try retrieving name file %s\n", dir);
12565 RETRIEVE(dir, -1, mailbox, context);
12566 if (ast_fileexists(dir, NULL, NULL)) {
12567 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12568 }
12569 DISPOSE(dir, -1);
12570 return res;
12571 }
12572
12573 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12574 struct ast_config *pwconf;
12575 struct ast_flags config_flags = { 0 };
12576
12577 pwconf = ast_config_load(secretfn, config_flags);
12578 if (valid_config(pwconf)) {
12579 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12580 if (val) {
12581 ast_copy_string(password, val, passwordlen);
12582 ast_config_destroy(pwconf);
12583 return;
12584 }
12585 ast_config_destroy(pwconf);
12586 }
12587 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12588 }
12589
12590 static int write_password_to_file(const char *secretfn, const char *password) {
12591 struct ast_config *conf;
12592 struct ast_category *cat;
12593 struct ast_variable *var;
12594 int res = -1;
12595
12596 if (!(conf = ast_config_new())) {
12597 ast_log(LOG_ERROR, "Error creating new config structure\n");
12598 return res;
12599 }
12600 if (!(cat = ast_category_new("general", "", 1))) {
12601 ast_log(LOG_ERROR, "Error creating new category structure\n");
12602 ast_config_destroy(conf);
12603 return res;
12604 }
12605 if (!(var = ast_variable_new("password", password, ""))) {
12606 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12607 ast_config_destroy(conf);
12608 ast_category_destroy(cat);
12609 return res;
12610 }
12611 ast_category_append(conf, cat);
12612 ast_variable_append(cat, var);
12613 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12614 res = 0;
12615 } else {
12616 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12617 }
12618
12619 ast_config_destroy(conf);
12620 return res;
12621 }
12622
12623 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12624 {
12625 char *context;
12626 char *args_copy;
12627 int res;
12628
12629 if (ast_strlen_zero(data)) {
12630 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12631 return -1;
12632 }
12633
12634 args_copy = ast_strdupa(data);
12635 if ((context = strchr(args_copy, '@'))) {
12636 *context++ = '\0';
12637 } else {
12638 context = "default";
12639 }
12640
12641 if ((res = sayname(chan, args_copy, context) < 0)) {
12642 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12643 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12644 if (!res) {
12645 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12646 }
12647 }
12648
12649 return res;
12650 }
12651
12652 #ifdef TEST_FRAMEWORK
12653 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12654 {
12655 return 0;
12656 }
12657
12658 static struct ast_frame *fake_read(struct ast_channel *ast)
12659 {
12660 return &ast_null_frame;
12661 }
12662
12663 AST_TEST_DEFINE(test_voicemail_vmsayname)
12664 {
12665 char dir[PATH_MAX];
12666 char dir2[PATH_MAX];
12667 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12668 static const char TEST_EXTENSION[] = "1234";
12669
12670 struct ast_channel *test_channel1 = NULL;
12671 int res = -1;
12672
12673 static const struct ast_channel_tech fake_tech = {
12674 .write = fake_write,
12675 .read = fake_read,
12676 };
12677
12678 switch (cmd) {
12679 case TEST_INIT:
12680 info->name = "vmsayname_exec";
12681 info->category = "/apps/app_voicemail/";
12682 info->summary = "Vmsayname unit test";
12683 info->description =
12684 "This tests passing various parameters to vmsayname";
12685 return AST_TEST_NOT_RUN;
12686 case TEST_EXECUTE:
12687 break;
12688 }
12689
12690 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12691 NULL, NULL, 0, 0, "TestChannel1"))) {
12692 goto exit_vmsayname_test;
12693 }
12694
12695
12696 test_channel1->nativeformats = AST_FORMAT_GSM;
12697 test_channel1->writeformat = AST_FORMAT_GSM;
12698 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12699 test_channel1->readformat = AST_FORMAT_GSM;
12700 test_channel1->rawreadformat = AST_FORMAT_GSM;
12701 test_channel1->tech = &fake_tech;
12702
12703 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12704 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12705 if (!(res = vmsayname_exec(test_channel1, dir))) {
12706 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12707 if (ast_fileexists(dir, NULL, NULL)) {
12708 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12709 res = -1;
12710 goto exit_vmsayname_test;
12711 } else {
12712
12713 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12714 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12715 goto exit_vmsayname_test;
12716 }
12717 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12718 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12719
12720 if ((res = symlink(dir, dir2))) {
12721 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12722 goto exit_vmsayname_test;
12723 }
12724 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12725 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12726 res = vmsayname_exec(test_channel1, dir);
12727
12728
12729 unlink(dir2);
12730 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12731 rmdir(dir2);
12732 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12733 rmdir(dir2);
12734 }
12735 }
12736
12737 exit_vmsayname_test:
12738
12739 if (test_channel1) {
12740 ast_hangup(test_channel1);
12741 }
12742
12743 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12744 }
12745
12746 AST_TEST_DEFINE(test_voicemail_msgcount)
12747 {
12748 int i, j, res = AST_TEST_PASS, syserr;
12749 struct ast_vm_user *vmu;
12750 struct ast_vm_user svm;
12751 struct vm_state vms;
12752 #ifdef IMAP_STORAGE
12753 struct ast_channel *chan = NULL;
12754 #endif
12755 struct {
12756 char dir[256];
12757 char file[256];
12758 char txtfile[256];
12759 } tmp[3];
12760 char syscmd[256];
12761 const char origweasels[] = "tt-weasels";
12762 const char testcontext[] = "test";
12763 const char testmailbox[] = "00000000";
12764 const char testspec[] = "00000000@test";
12765 FILE *txt;
12766 int new, old, urgent;
12767 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12768 const int folder2mbox[3] = { 1, 11, 0 };
12769 const int expected_results[3][12] = {
12770
12771 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12772 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12773 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12774 };
12775
12776 switch (cmd) {
12777 case TEST_INIT:
12778 info->name = "test_voicemail_msgcount";
12779 info->category = "/apps/app_voicemail/";
12780 info->summary = "Test Voicemail status checks";
12781 info->description =
12782 "Verify that message counts are correct when retrieved through the public API";
12783 return AST_TEST_NOT_RUN;
12784 case TEST_EXECUTE:
12785 break;
12786 }
12787
12788
12789 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12790 if ((syserr = ast_safe_system(syscmd))) {
12791 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12792 syserr > 0 ? strerror(syserr) : "unable to fork()");
12793 return AST_TEST_FAIL;
12794 }
12795
12796 #ifdef IMAP_STORAGE
12797 if (!(chan = ast_dummy_channel_alloc())) {
12798 ast_test_status_update(test, "Unable to create dummy channel\n");
12799 return AST_TEST_FAIL;
12800 }
12801 #endif
12802
12803 if (!(vmu = find_user(&svm, testcontext, testmailbox)) &&
12804 !(vmu = find_or_create(testcontext, testmailbox))) {
12805 ast_test_status_update(test, "Cannot create vmu structure\n");
12806 ast_unreplace_sigchld();
12807 #ifdef IMAP_STORAGE
12808 chan = ast_channel_unref(chan);
12809 #endif
12810 return AST_TEST_FAIL;
12811 }
12812
12813 populate_defaults(vmu);
12814 memset(&vms, 0, sizeof(vms));
12815
12816
12817 for (i = 0; i < 3; i++) {
12818 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12819 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12820 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12821
12822 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12823 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12824 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12825 if ((syserr = ast_safe_system(syscmd))) {
12826 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12827 syserr > 0 ? strerror(syserr) : "unable to fork()");
12828 ast_unreplace_sigchld();
12829 #ifdef IMAP_STORAGE
12830 chan = ast_channel_unref(chan);
12831 #endif
12832 return AST_TEST_FAIL;
12833 }
12834 }
12835
12836 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12837 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12838 fclose(txt);
12839 } else {
12840 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12841 res = AST_TEST_FAIL;
12842 break;
12843 }
12844 open_mailbox(&vms, vmu, folder2mbox[i]);
12845 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12846
12847
12848 for (j = 0; j < 3; j++) {
12849
12850 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12851 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12852 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12853 res = AST_TEST_FAIL;
12854 }
12855 }
12856
12857 new = old = urgent = 0;
12858 if (ast_app_inboxcount(testspec, &new, &old)) {
12859 ast_test_status_update(test, "inboxcount returned failure\n");
12860 res = AST_TEST_FAIL;
12861 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12862 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12863 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12864 res = AST_TEST_FAIL;
12865 }
12866
12867 new = old = urgent = 0;
12868 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12869 ast_test_status_update(test, "inboxcount2 returned failure\n");
12870 res = AST_TEST_FAIL;
12871 } else if (old != expected_results[i][6 + 0] ||
12872 urgent != expected_results[i][6 + 1] ||
12873 new != expected_results[i][6 + 2] ) {
12874 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12875 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12876 res = AST_TEST_FAIL;
12877 }
12878
12879 new = old = urgent = 0;
12880 for (j = 0; j < 3; j++) {
12881 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12882 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12883 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12884 res = AST_TEST_FAIL;
12885 }
12886 }
12887 }
12888
12889 for (i = 0; i < 3; i++) {
12890
12891
12892
12893 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12894 DISPOSE(tmp[i].dir, 0);
12895 }
12896
12897 if (vms.deleted) {
12898 ast_free(vms.deleted);
12899 }
12900 if (vms.heard) {
12901 ast_free(vms.heard);
12902 }
12903
12904 #ifdef IMAP_STORAGE
12905 chan = ast_channel_unref(chan);
12906 #endif
12907
12908
12909 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12910 if ((syserr = ast_safe_system(syscmd))) {
12911 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12912 syserr > 0 ? strerror(syserr) : "unable to fork()");
12913 }
12914
12915 return res;
12916 }
12917
12918 AST_TEST_DEFINE(test_voicemail_notify_endl)
12919 {
12920 int res = AST_TEST_PASS;
12921 char testcontext[] = "test";
12922 char testmailbox[] = "00000000";
12923 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12924 char attach[256], attach2[256];
12925 char buf[256] = "";
12926 struct ast_channel *chan = NULL;
12927 struct ast_vm_user *vmu, vmus = {
12928 .flags = 0,
12929 };
12930 FILE *file;
12931 struct {
12932 char *name;
12933 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12934 void *location;
12935 union {
12936 int intval;
12937 char *strval;
12938 } u;
12939 } test_items[] = {
12940 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12941 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12942 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12943 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12944 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12945 { "attach2", STRPTR, attach2, .u.strval = "" },
12946 { "attach", STRPTR, attach, .u.strval = "" },
12947 };
12948 int which;
12949
12950 switch (cmd) {
12951 case TEST_INIT:
12952 info->name = "test_voicemail_notify_endl";
12953 info->category = "/apps/app_voicemail/";
12954 info->summary = "Test Voicemail notification end-of-line";
12955 info->description =
12956 "Verify that notification emails use a consistent end-of-line character";
12957 return AST_TEST_NOT_RUN;
12958 case TEST_EXECUTE:
12959 break;
12960 }
12961
12962 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12963 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12964
12965 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12966 !(vmu = find_or_create(testcontext, testmailbox))) {
12967 ast_test_status_update(test, "Cannot create vmu structure\n");
12968 return AST_TEST_NOT_RUN;
12969 }
12970
12971 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12972 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12973 return AST_TEST_NOT_RUN;
12974 }
12975
12976 populate_defaults(vmu);
12977 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12978 #ifdef IMAP_STORAGE
12979
12980 #endif
12981
12982 file = tmpfile();
12983 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12984
12985 rewind(file);
12986 if (ftruncate(fileno(file), 0)) {
12987 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12988 res = AST_TEST_FAIL;
12989 break;
12990 }
12991
12992
12993 if (test_items[which].type == INT) {
12994 *((int *) test_items[which].location) = test_items[which].u.intval;
12995 } else if (test_items[which].type == FLAGVAL) {
12996 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12997 ast_clear_flag(vmu, test_items[which].u.intval);
12998 } else {
12999 ast_set_flag(vmu, test_items[which].u.intval);
13000 }
13001 } else if (test_items[which].type == STATIC) {
13002 strcpy(test_items[which].location, test_items[which].u.strval);
13003 } else if (test_items[which].type == STRPTR) {
13004 test_items[which].location = test_items[which].u.strval;
13005 }
13006
13007 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
13008 rewind(file);
13009 while (fgets(buf, sizeof(buf), file)) {
13010 if (
13011 #ifdef IMAP_STORAGE
13012 buf[strlen(buf) - 2] != '\r'
13013 #else
13014 buf[strlen(buf) - 2] == '\r'
13015 #endif
13016 || buf[strlen(buf) - 1] != '\n') {
13017 res = AST_TEST_FAIL;
13018 }
13019 }
13020 }
13021 fclose(file);
13022 return res;
13023 }
13024
13025 AST_TEST_DEFINE(test_voicemail_load_config)
13026 {
13027 int res = AST_TEST_PASS;
13028 struct ast_vm_user *vmu;
13029 struct ast_config *cfg;
13030 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
13031 int fd;
13032 FILE *file;
13033 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
13034
13035 switch (cmd) {
13036 case TEST_INIT:
13037 info->name = "test_voicemail_load_config";
13038 info->category = "/apps/app_voicemail/";
13039 info->summary = "Test loading Voicemail config";
13040 info->description =
13041 "Verify that configuration is loaded consistently. "
13042 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13043 "some options were loaded after the mailboxes were instantiated, causing "
13044 "those options not to be set correctly.";
13045 return AST_TEST_NOT_RUN;
13046 case TEST_EXECUTE:
13047 break;
13048 }
13049
13050
13051 if ((fd = mkstemp(config_filename)) < 0) {
13052 return AST_TEST_FAIL;
13053 }
13054 if (!(file = fdopen(fd, "w"))) {
13055 close(fd);
13056 unlink(config_filename);
13057 return AST_TEST_FAIL;
13058 }
13059 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13060 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13061 fputs("00000002 => 9999,Mrs. Test\n", file);
13062 fclose(file);
13063
13064 if (!(cfg = ast_config_load(config_filename, config_flags)) || !valid_config(cfg)) {
13065 res = AST_TEST_FAIL;
13066 goto cleanup;
13067 }
13068
13069 load_config_from_memory(1, cfg, NULL);
13070 ast_config_destroy(cfg);
13071
13072 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13073 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13074 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13075
13076 AST_LIST_LOCK(&users);
13077 AST_LIST_TRAVERSE(&users, vmu, list) {
13078 if (!strcmp(vmu->mailbox, "00000001")) {
13079 if (0);
13080 CHECK(vmu, callback, "othercontext")
13081 CHECK(vmu, locale, "nl_NL.UTF-8")
13082 CHECK(vmu, zonetag, "central")
13083 } else if (!strcmp(vmu->mailbox, "00000002")) {
13084 if (0);
13085 CHECK(vmu, callback, "somecontext")
13086 CHECK(vmu, locale, "de_DE.UTF-8")
13087 CHECK(vmu, zonetag, "european")
13088 }
13089 }
13090 AST_LIST_UNLOCK(&users);
13091
13092 #undef CHECK
13093
13094
13095 load_config(1);
13096
13097 cleanup:
13098 unlink(config_filename);
13099 return res;
13100 }
13101
13102 #endif
13103
13104 static int reload(void)
13105 {
13106 return load_config(1);
13107 }
13108
13109 static int unload_module(void)
13110 {
13111 int res;
13112
13113 res = ast_unregister_application(app);
13114 res |= ast_unregister_application(app2);
13115 res |= ast_unregister_application(app3);
13116 res |= ast_unregister_application(app4);
13117 res |= ast_unregister_application(sayname_app);
13118 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13119 res |= ast_manager_unregister("VoicemailUsersList");
13120 res |= ast_data_unregister(NULL);
13121 #ifdef TEST_FRAMEWORK
13122 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13123 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13124 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13125 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13126 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13127 #endif
13128 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13129 ast_uninstall_vm_functions();
13130 ao2_ref(inprocess_container, -1);
13131
13132 if (poll_thread != AST_PTHREADT_NULL)
13133 stop_poll_thread();
13134
13135 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13136 ast_unload_realtime("voicemail");
13137 ast_unload_realtime("voicemail_data");
13138
13139 free_vm_users();
13140 free_vm_zones();
13141 return res;
13142 }
13143
13144 static int load_module(void)
13145 {
13146 int res;
13147 my_umask = umask(0);
13148 umask(my_umask);
13149
13150 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13151 return AST_MODULE_LOAD_DECLINE;
13152 }
13153
13154
13155 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13156
13157 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13158 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13159 }
13160
13161 if ((res = load_config(0)))
13162 return res;
13163
13164 res = ast_register_application_xml(app, vm_exec);
13165 res |= ast_register_application_xml(app2, vm_execmain);
13166 res |= ast_register_application_xml(app3, vm_box_exists);
13167 res |= ast_register_application_xml(app4, vmauthenticate);
13168 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13169 res |= ast_custom_function_register(&mailbox_exists_acf);
13170 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13171 #ifdef TEST_FRAMEWORK
13172 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13173 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13174 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13175 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13176 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13177 #endif
13178
13179 if (res)
13180 return res;
13181
13182 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13183 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13184
13185 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13186 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13187 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13188
13189 return res;
13190 }
13191
13192 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13193 {
13194 int cmd = 0;
13195 char destination[80] = "";
13196 int retries = 0;
13197
13198 if (!num) {
13199 ast_verb(3, "Destination number will be entered manually\n");
13200 while (retries < 3 && cmd != 't') {
13201 destination[1] = '\0';
13202 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13203 if (!cmd)
13204 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13205 if (!cmd)
13206 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13207 if (!cmd) {
13208 cmd = ast_waitfordigit(chan, 6000);
13209 if (cmd)
13210 destination[0] = cmd;
13211 }
13212 if (!cmd) {
13213 retries++;
13214 } else {
13215
13216 if (cmd < 0)
13217 return 0;
13218 if (cmd == '*') {
13219 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13220 return 0;
13221 }
13222 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13223 retries++;
13224 else
13225 cmd = 't';
13226 }
13227 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13228 }
13229 if (retries >= 3) {
13230 return 0;
13231 }
13232
13233 } else {
13234 if (option_verbose > 2)
13235 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13236 ast_copy_string(destination, num, sizeof(destination));
13237 }
13238
13239 if (!ast_strlen_zero(destination)) {
13240 if (destination[strlen(destination) -1 ] == '*')
13241 return 0;
13242 if (option_verbose > 2)
13243 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13244 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13245 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13246 chan->priority = 0;
13247 return 9;
13248 }
13249 return 0;
13250 }
13251
13252
13253
13254
13255
13256
13257
13258
13259
13260
13261
13262
13263
13264
13265 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)
13266 {
13267 int res = 0;
13268 char filename[PATH_MAX];
13269 struct ast_config *msg_cfg = NULL;
13270 const char *origtime, *context;
13271 char *name, *num;
13272 int retries = 0;
13273 char *cid;
13274 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13275
13276 vms->starting = 0;
13277
13278 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13279
13280
13281 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13282 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13283 msg_cfg = ast_config_load(filename, config_flags);
13284 DISPOSE(vms->curdir, vms->curmsg);
13285 if (!valid_config(msg_cfg)) {
13286 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13287 return 0;
13288 }
13289
13290 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13291 ast_config_destroy(msg_cfg);
13292 return 0;
13293 }
13294
13295 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13296
13297 context = ast_variable_retrieve(msg_cfg, "message", "context");
13298 if (!strncasecmp("macro", context, 5))
13299 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13300 switch (option) {
13301 case 3:
13302 if (!res)
13303 res = play_message_datetime(chan, vmu, origtime, filename);
13304 if (!res)
13305 res = play_message_callerid(chan, vms, cid, context, 0);
13306
13307 res = 't';
13308 break;
13309
13310 case 2:
13311
13312 if (ast_strlen_zero(cid))
13313 break;
13314
13315 ast_callerid_parse(cid, &name, &num);
13316 while ((res > -1) && (res != 't')) {
13317 switch (res) {
13318 case '1':
13319 if (num) {
13320
13321 res = dialout(chan, vmu, num, vmu->callback);
13322 if (res) {
13323 ast_config_destroy(msg_cfg);
13324 return 9;
13325 }
13326 } else {
13327 res = '2';
13328 }
13329 break;
13330
13331 case '2':
13332
13333 if (!ast_strlen_zero(vmu->dialout)) {
13334 res = dialout(chan, vmu, NULL, vmu->dialout);
13335 if (res) {
13336 ast_config_destroy(msg_cfg);
13337 return 9;
13338 }
13339 } else {
13340 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13341 res = ast_play_and_wait(chan, "vm-sorry");
13342 }
13343 ast_config_destroy(msg_cfg);
13344 return res;
13345 case '*':
13346 res = 't';
13347 break;
13348 case '3':
13349 case '4':
13350 case '5':
13351 case '6':
13352 case '7':
13353 case '8':
13354 case '9':
13355 case '0':
13356
13357 res = ast_play_and_wait(chan, "vm-sorry");
13358 retries++;
13359 break;
13360 default:
13361 if (num) {
13362 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13363 res = ast_play_and_wait(chan, "vm-num-i-have");
13364 if (!res)
13365 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13366 if (!res)
13367 res = ast_play_and_wait(chan, "vm-tocallnum");
13368
13369 if (!ast_strlen_zero(vmu->dialout)) {
13370 if (!res)
13371 res = ast_play_and_wait(chan, "vm-calldiffnum");
13372 }
13373 } else {
13374 res = ast_play_and_wait(chan, "vm-nonumber");
13375 if (!ast_strlen_zero(vmu->dialout)) {
13376 if (!res)
13377 res = ast_play_and_wait(chan, "vm-toenternumber");
13378 }
13379 }
13380 if (!res) {
13381 res = ast_play_and_wait(chan, "vm-star-cancel");
13382 }
13383 if (!res) {
13384 res = ast_waitfordigit(chan, 6000);
13385 }
13386 if (!res) {
13387 retries++;
13388 if (retries > 3) {
13389 res = 't';
13390 }
13391 }
13392 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13393 break;
13394
13395 }
13396 if (res == 't')
13397 res = 0;
13398 else if (res == '*')
13399 res = -1;
13400 }
13401 break;
13402
13403 case 1:
13404
13405 if (ast_strlen_zero(cid))
13406 break;
13407
13408 ast_callerid_parse(cid, &name, &num);
13409 if (!num) {
13410 ast_verb(3, "No CID number available, no reply sent\n");
13411 if (!res)
13412 res = ast_play_and_wait(chan, "vm-nonumber");
13413 ast_config_destroy(msg_cfg);
13414 return res;
13415 } else {
13416 struct ast_vm_user vmu2;
13417 if (find_user(&vmu2, vmu->context, num)) {
13418 struct leave_vm_options leave_options;
13419 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13420 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13421
13422 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13423
13424 memset(&leave_options, 0, sizeof(leave_options));
13425 leave_options.record_gain = record_gain;
13426 res = leave_voicemail(chan, mailbox, &leave_options);
13427 if (!res)
13428 res = 't';
13429 ast_config_destroy(msg_cfg);
13430 return res;
13431 } else {
13432
13433 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13434 ast_play_and_wait(chan, "vm-nobox");
13435 res = 't';
13436 ast_config_destroy(msg_cfg);
13437 return res;
13438 }
13439 }
13440 res = 0;
13441
13442 break;
13443 }
13444
13445 ast_config_destroy(msg_cfg);
13446
13447 #ifndef IMAP_STORAGE
13448 if (!res) {
13449 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13450 vms->heard[msg] = 1;
13451 res = wait_file(chan, vms, vms->fn);
13452 }
13453 #endif
13454 return res;
13455 }
13456
13457 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13458 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13459 signed char record_gain, struct vm_state *vms, char *flag)
13460 {
13461
13462 int res = 0;
13463 int cmd = 0;
13464 int max_attempts = 3;
13465 int attempts = 0;
13466 int recorded = 0;
13467 int msg_exists = 0;
13468 signed char zero_gain = 0;
13469 char tempfile[PATH_MAX];
13470 char *acceptdtmf = "#";
13471 char *canceldtmf = "";
13472 int canceleddtmf = 0;
13473
13474
13475
13476
13477 if (duration == NULL) {
13478 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13479 return -1;
13480 }
13481
13482 if (!outsidecaller)
13483 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13484 else
13485 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13486
13487 cmd = '3';
13488
13489 while ((cmd >= 0) && (cmd != 't')) {
13490 switch (cmd) {
13491 case '1':
13492 if (!msg_exists) {
13493
13494 cmd = '3';
13495 break;
13496 } else {
13497
13498 ast_verb(3, "Saving message as is\n");
13499 if (!outsidecaller)
13500 ast_filerename(tempfile, recordfile, NULL);
13501 ast_stream_and_wait(chan, "vm-msgsaved", "");
13502 if (!outsidecaller) {
13503
13504 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13505 DISPOSE(recordfile, -1);
13506 }
13507 cmd = 't';
13508 return res;
13509 }
13510 case '2':
13511
13512 ast_verb(3, "Reviewing the message\n");
13513 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13514 break;
13515 case '3':
13516 msg_exists = 0;
13517
13518 if (recorded == 1)
13519 ast_verb(3, "Re-recording the message\n");
13520 else
13521 ast_verb(3, "Recording the message\n");
13522
13523 if (recorded && outsidecaller) {
13524 cmd = ast_play_and_wait(chan, INTRO);
13525 cmd = ast_play_and_wait(chan, "beep");
13526 }
13527 recorded = 1;
13528
13529 if (record_gain)
13530 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13531 if (ast_test_flag(vmu, VM_OPERATOR))
13532 canceldtmf = "0";
13533 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13534 if (strchr(canceldtmf, cmd)) {
13535
13536 canceleddtmf = 1;
13537 }
13538 if (record_gain)
13539 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13540 if (cmd == -1) {
13541
13542 if (!outsidecaller) {
13543
13544 ast_filedelete(tempfile, NULL);
13545 }
13546 return cmd;
13547 }
13548 if (cmd == '0') {
13549 break;
13550 } else if (cmd == '*') {
13551 break;
13552 #if 0
13553 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13554
13555 ast_verb(3, "Message too short\n");
13556 cmd = ast_play_and_wait(chan, "vm-tooshort");
13557 cmd = ast_filedelete(tempfile, NULL);
13558 break;
13559 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13560
13561 ast_verb(3, "Nothing recorded\n");
13562 cmd = ast_filedelete(tempfile, NULL);
13563 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13564 if (!cmd)
13565 cmd = ast_play_and_wait(chan, "vm-speakup");
13566 break;
13567 #endif
13568 } else {
13569
13570 msg_exists = 1;
13571 cmd = 0;
13572 }
13573 break;
13574 case '4':
13575 if (outsidecaller) {
13576
13577 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13578 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13579 res = ast_play_and_wait(chan, "vm-marked-urgent");
13580 strcpy(flag, "Urgent");
13581 } else if (flag) {
13582 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13583 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
13584 strcpy(flag, "");
13585 } else {
13586 ast_play_and_wait(chan, "vm-sorry");
13587 }
13588 cmd = 0;
13589 } else {
13590 cmd = ast_play_and_wait(chan, "vm-sorry");
13591 }
13592 break;
13593 case '5':
13594 case '6':
13595 case '7':
13596 case '8':
13597 case '9':
13598 case '*':
13599 case '#':
13600 cmd = ast_play_and_wait(chan, "vm-sorry");
13601 break;
13602 #if 0
13603
13604
13605 case '*':
13606
13607 cmd = ast_play_and_wait(chan, "vm-deleted");
13608 cmd = ast_filedelete(tempfile, NULL);
13609 if (outsidecaller) {
13610 res = vm_exec(chan, NULL);
13611 return res;
13612 }
13613 else
13614 return 1;
13615 #endif
13616 case '0':
13617 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13618 cmd = ast_play_and_wait(chan, "vm-sorry");
13619 break;
13620 }
13621 if (msg_exists || recorded) {
13622 cmd = ast_play_and_wait(chan, "vm-saveoper");
13623 if (!cmd)
13624 cmd = ast_waitfordigit(chan, 3000);
13625 if (cmd == '1') {
13626 ast_filerename(tempfile, recordfile, NULL);
13627 ast_play_and_wait(chan, "vm-msgsaved");
13628 cmd = '0';
13629 } else if (cmd == '4') {
13630 if (flag) {
13631 ast_play_and_wait(chan, "vm-marked-urgent");
13632 strcpy(flag, "Urgent");
13633 }
13634 ast_play_and_wait(chan, "vm-msgsaved");
13635 cmd = '0';
13636 } else {
13637 ast_play_and_wait(chan, "vm-deleted");
13638 DELETE(tempfile, -1, tempfile, vmu);
13639 cmd = '0';
13640 }
13641 }
13642 return cmd;
13643 default:
13644
13645
13646
13647 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13648 return cmd;
13649 if (msg_exists) {
13650 cmd = ast_play_and_wait(chan, "vm-review");
13651 if (!cmd && outsidecaller) {
13652 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13653 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13654 } else if (flag) {
13655 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13656 }
13657 }
13658 } else {
13659 cmd = ast_play_and_wait(chan, "vm-torerecord");
13660 if (!cmd)
13661 cmd = ast_waitfordigit(chan, 600);
13662 }
13663
13664 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13665 cmd = ast_play_and_wait(chan, "vm-reachoper");
13666 if (!cmd)
13667 cmd = ast_waitfordigit(chan, 600);
13668 }
13669 #if 0
13670 if (!cmd)
13671 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13672 #endif
13673 if (!cmd)
13674 cmd = ast_waitfordigit(chan, 6000);
13675 if (!cmd) {
13676 attempts++;
13677 }
13678 if (attempts > max_attempts) {
13679 cmd = 't';
13680 }
13681 }
13682 }
13683 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13684
13685 ast_filedelete(tempfile, NULL);
13686 }
13687
13688 if (cmd != 't' && outsidecaller)
13689 ast_play_and_wait(chan, "vm-goodbye");
13690
13691 return cmd;
13692 }
13693
13694
13695
13696
13697
13698 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13699 .load = load_module,
13700 .unload = unload_module,
13701 .reload = reload,
13702 .nonoptreq = "res_adsi,res_smdi",
13703 );