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/1");
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/1");
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 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09565 {
09566 int cmd = 0;
09567
09568 if (vms->lastmsg > -1) {
09569 cmd = play_message(chan, vmu, vms);
09570 } else {
09571 if (!strcasecmp(vms->fn, "INBOX")) {
09572 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09573 } else {
09574 cmd = ast_play_and_wait(chan, "vm-nomessages");
09575 }
09576 }
09577 return cmd;
09578 }
09579
09580
09581
09582
09583
09584
09585
09586
09587
09588 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09589 {
09590 int cmd = 0;
09591
09592 if (vms->lastmsg > -1) {
09593 cmd = play_message(chan, vmu, vms);
09594 } else {
09595 cmd = ast_play_and_wait(chan, "vm-youhave");
09596 if (!cmd)
09597 cmd = ast_play_and_wait(chan, "vm-no");
09598 if (!cmd) {
09599 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09600 cmd = ast_play_and_wait(chan, vms->fn);
09601 }
09602 if (!cmd)
09603 cmd = ast_play_and_wait(chan, "vm-messages");
09604 }
09605 return cmd;
09606 }
09607
09608
09609
09610
09611
09612
09613
09614
09615
09616
09617 static int vm_browse_messages_latin(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09618 {
09619 int cmd;
09620
09621 if (vms->lastmsg > -1) {
09622 cmd = play_message(chan, vmu, vms);
09623 } else {
09624 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09625 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09626 if (!cmd) {
09627 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09628 cmd = ast_play_and_wait(chan, vms->fn);
09629 }
09630 if (!cmd)
09631 cmd = ast_play_and_wait(chan, "vm-messages");
09632 } else {
09633 if (!cmd)
09634 cmd = ast_play_and_wait(chan, "vm-messages");
09635 if (!cmd) {
09636 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09637 cmd = ast_play_and_wait(chan, vms->fn);
09638 }
09639 }
09640 }
09641 return cmd;
09642 }
09643
09644
09645
09646
09647
09648
09649
09650
09651
09652 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09653 {
09654 int cmd;
09655
09656 if (vms->lastmsg > -1) {
09657 cmd = play_message(chan, vmu, vms);
09658 } else {
09659 cmd = ast_play_and_wait(chan, "vm-you");
09660 if (!cmd)
09661 cmd = ast_play_and_wait(chan, "vm-haveno");
09662 if (!cmd)
09663 cmd = ast_play_and_wait(chan, "vm-messages");
09664 if (!cmd) {
09665 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09666 cmd = ast_play_and_wait(chan, vms->fn);
09667 }
09668 }
09669 return cmd;
09670 }
09671
09672
09673
09674
09675
09676
09677
09678
09679
09680 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09681 {
09682 int cmd = 0;
09683
09684 if (vms->lastmsg > -1) {
09685 cmd = play_message(chan, vmu, vms);
09686 } else {
09687 cmd = ast_play_and_wait(chan, "vm-no");
09688 if (!cmd) {
09689 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09690 cmd = ast_play_and_wait(chan, vms->fn);
09691 }
09692 }
09693 return cmd;
09694 }
09695
09696
09697
09698
09699
09700
09701
09702
09703
09704
09705
09706
09707 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09708 {
09709 if (!strncasecmp(chan->language, "es", 2) ||
09710 !strncasecmp(chan->language, "it", 2) ||
09711 !strncasecmp(chan->language, "pt", 2) ||
09712 !strncasecmp(chan->language, "gr", 2)) {
09713 return vm_browse_messages_latin(chan, vms, vmu);
09714 } else if (!strncasecmp(chan->language, "he", 2)) {
09715 return vm_browse_messages_he(chan, vms, vmu);
09716 } else if (!strncasecmp(chan->language, "vi", 2)) {
09717 return vm_browse_messages_vi(chan, vms, vmu);
09718 } else if (!strncasecmp(chan->language, "zh", 2)) {
09719 return vm_browse_messages_zh(chan, vms, vmu);
09720 } else {
09721 return vm_browse_messages_en(chan, vms, vmu);
09722 }
09723 }
09724
09725 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09726 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09727 int skipuser, int max_logins, int silent)
09728 {
09729 int useadsi = 0, valid = 0, logretries = 0;
09730 char password[AST_MAX_EXTENSION]="", *passptr;
09731 struct ast_vm_user vmus, *vmu = NULL;
09732
09733
09734 adsi_begin(chan, &useadsi);
09735 if (!skipuser && useadsi)
09736 adsi_login(chan);
09737 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09738 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09739 return -1;
09740 }
09741
09742
09743
09744 while (!valid && (logretries < max_logins)) {
09745
09746 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09747 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09748 return -1;
09749 }
09750 if (ast_strlen_zero(mailbox)) {
09751 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09752 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09753 } else {
09754 ast_verb(3, "Username not entered\n");
09755 return -1;
09756 }
09757 } else if (mailbox[0] == '*') {
09758
09759 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09760 if (ast_exists_extension(chan, chan->context, "a", 1,
09761 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09762 return -1;
09763 }
09764 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09765 mailbox[0] = '\0';
09766 }
09767
09768 if (useadsi)
09769 adsi_password(chan);
09770
09771 if (!ast_strlen_zero(prefix)) {
09772 char fullusername[80] = "";
09773 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09774 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09775 ast_copy_string(mailbox, fullusername, mailbox_size);
09776 }
09777
09778 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09779 vmu = find_user(&vmus, context, mailbox);
09780 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09781
09782 password[0] = '\0';
09783 } else {
09784 if (ast_streamfile(chan, vm_password, chan->language)) {
09785 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09786 return -1;
09787 }
09788 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09789 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09790 return -1;
09791 } else if (password[0] == '*') {
09792
09793 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09794 if (ast_exists_extension(chan, chan->context, "a", 1,
09795 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09796 mailbox[0] = '*';
09797 return -1;
09798 }
09799 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09800 mailbox[0] = '\0';
09801
09802 vmu = NULL;
09803 }
09804 }
09805
09806 if (vmu) {
09807 passptr = vmu->password;
09808 if (passptr[0] == '-') passptr++;
09809 }
09810 if (vmu && !strcmp(passptr, password))
09811 valid++;
09812 else {
09813 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09814 if (!ast_strlen_zero(prefix))
09815 mailbox[0] = '\0';
09816 }
09817 logretries++;
09818 if (!valid) {
09819 if (skipuser || logretries >= max_logins) {
09820 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09821 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09822 return -1;
09823 }
09824 } else {
09825 if (useadsi)
09826 adsi_login(chan);
09827 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09828 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09829 return -1;
09830 }
09831 }
09832 if (ast_waitstream(chan, ""))
09833 return -1;
09834 }
09835 }
09836 if (!valid && (logretries >= max_logins)) {
09837 ast_stopstream(chan);
09838 ast_play_and_wait(chan, "vm-goodbye");
09839 return -1;
09840 }
09841 if (vmu && !skipuser) {
09842 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09843 }
09844 return 0;
09845 }
09846
09847 static int vm_execmain(struct ast_channel *chan, const char *data)
09848 {
09849
09850
09851
09852 int res = -1;
09853 int cmd = 0;
09854 int valid = 0;
09855 char prefixstr[80] ="";
09856 char ext_context[256]="";
09857 int box;
09858 int useadsi = 0;
09859 int skipuser = 0;
09860 struct vm_state vms;
09861 struct ast_vm_user *vmu = NULL, vmus;
09862 char *context = NULL;
09863 int silentexit = 0;
09864 struct ast_flags flags = { 0 };
09865 signed char record_gain = 0;
09866 int play_auto = 0;
09867 int play_folder = 0;
09868 int in_urgent = 0;
09869 #ifdef IMAP_STORAGE
09870 int deleted = 0;
09871 #endif
09872
09873
09874 memset(&vms, 0, sizeof(vms));
09875
09876 vms.lastmsg = -1;
09877
09878 memset(&vmus, 0, sizeof(vmus));
09879
09880 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09881 if (chan->_state != AST_STATE_UP) {
09882 ast_debug(1, "Before ast_answer\n");
09883 ast_answer(chan);
09884 }
09885
09886 if (!ast_strlen_zero(data)) {
09887 char *opts[OPT_ARG_ARRAY_SIZE];
09888 char *parse;
09889 AST_DECLARE_APP_ARGS(args,
09890 AST_APP_ARG(argv0);
09891 AST_APP_ARG(argv1);
09892 );
09893
09894 parse = ast_strdupa(data);
09895
09896 AST_STANDARD_APP_ARGS(args, parse);
09897
09898 if (args.argc == 2) {
09899 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09900 return -1;
09901 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09902 int gain;
09903 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09904 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09905 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09906 return -1;
09907 } else {
09908 record_gain = (signed char) gain;
09909 }
09910 } else {
09911 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09912 }
09913 }
09914 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09915 play_auto = 1;
09916 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09917
09918 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09919 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09920 play_folder = -1;
09921 }
09922 } else {
09923 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09924 }
09925 } else {
09926 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09927 }
09928 if (play_folder > 9 || play_folder < 0) {
09929 ast_log(AST_LOG_WARNING,
09930 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09931 opts[OPT_ARG_PLAYFOLDER]);
09932 play_folder = 0;
09933 }
09934 }
09935 } else {
09936
09937 while (*(args.argv0)) {
09938 if (*(args.argv0) == 's')
09939 ast_set_flag(&flags, OPT_SILENT);
09940 else if (*(args.argv0) == 'p')
09941 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09942 else
09943 break;
09944 (args.argv0)++;
09945 }
09946
09947 }
09948
09949 valid = ast_test_flag(&flags, OPT_SILENT);
09950
09951 if ((context = strchr(args.argv0, '@')))
09952 *context++ = '\0';
09953
09954 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09955 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09956 else
09957 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09958
09959 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09960 skipuser++;
09961 else
09962 valid = 0;
09963 }
09964
09965 if (!valid)
09966 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09967
09968 ast_debug(1, "After vm_authenticate\n");
09969
09970 if (vms.username[0] == '*') {
09971 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09972
09973
09974 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
09975 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
09976 res = 0;
09977 goto out;
09978 }
09979 }
09980
09981 if (!res) {
09982 valid = 1;
09983 if (!skipuser)
09984 vmu = &vmus;
09985 } else {
09986 res = 0;
09987 }
09988
09989
09990 adsi_begin(chan, &useadsi);
09991
09992 ast_test_suite_assert(valid);
09993 if (!valid) {
09994 goto out;
09995 }
09996 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
09997
09998 #ifdef IMAP_STORAGE
09999 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10000 pthread_setspecific(ts_vmstate.key, &vms);
10001
10002 vms.interactive = 1;
10003 vms.updated = 1;
10004 if (vmu)
10005 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10006 vmstate_insert(&vms);
10007 init_vm_state(&vms);
10008 #endif
10009
10010
10011 if (!ast_strlen_zero(vmu->language))
10012 ast_string_field_set(chan, language, vmu->language);
10013
10014
10015 ast_debug(1, "Before open_mailbox\n");
10016 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10017 if (res < 0)
10018 goto out;
10019 vms.oldmessages = vms.lastmsg + 1;
10020 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10021
10022 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10023 if (res < 0)
10024 goto out;
10025 vms.newmessages = vms.lastmsg + 1;
10026 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10027
10028 in_urgent = 1;
10029 res = open_mailbox(&vms, vmu, 11);
10030 if (res < 0)
10031 goto out;
10032 vms.urgentmessages = vms.lastmsg + 1;
10033 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10034
10035
10036 if (play_auto) {
10037 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10038 if (vms.urgentmessages) {
10039 in_urgent = 1;
10040 res = open_mailbox(&vms, vmu, 11);
10041 } else {
10042 in_urgent = 0;
10043 res = open_mailbox(&vms, vmu, play_folder);
10044 }
10045 if (res < 0)
10046 goto out;
10047
10048
10049 if (vms.lastmsg == -1) {
10050 in_urgent = 0;
10051 cmd = vm_browse_messages(chan, &vms, vmu);
10052 res = 0;
10053 goto out;
10054 }
10055 } else {
10056 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10057
10058 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10059 in_urgent = 0;
10060 play_folder = 1;
10061 if (res < 0)
10062 goto out;
10063 } else if (!vms.urgentmessages && vms.newmessages) {
10064
10065 in_urgent = 0;
10066 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10067 if (res < 0)
10068 goto out;
10069 }
10070 }
10071
10072 if (useadsi)
10073 adsi_status(chan, &vms);
10074 res = 0;
10075
10076
10077 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10078 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10079 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10080 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10081 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10082 if ((cmd == 't') || (cmd == '#')) {
10083
10084 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10085 res = 0;
10086 goto out;
10087 } else if (cmd < 0) {
10088
10089 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10090 res = -1;
10091 goto out;
10092 }
10093 }
10094 #ifdef IMAP_STORAGE
10095 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10096 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10097 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10098 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10099 }
10100 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10101 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10102 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10103 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10104 }
10105 #endif
10106
10107 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10108 if (play_auto) {
10109 cmd = '1';
10110 } else {
10111 cmd = vm_intro(chan, vmu, &vms);
10112 }
10113 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10114
10115 vms.repeats = 0;
10116 vms.starting = 1;
10117 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10118
10119 switch (cmd) {
10120 case '1':
10121 vms.curmsg = 0;
10122
10123 case '5':
10124 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10125 cmd = vm_browse_messages(chan, &vms, vmu);
10126 break;
10127 case '2':
10128 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10129 if (useadsi)
10130 adsi_folders(chan, 0, "Change to folder...");
10131
10132 cmd = get_folder2(chan, "vm-changeto", 0);
10133 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10134 if (cmd == '#') {
10135 cmd = 0;
10136 } else if (cmd > 0) {
10137 cmd = cmd - '0';
10138 res = close_mailbox(&vms, vmu);
10139 if (res == ERROR_LOCK_PATH)
10140 goto out;
10141
10142 if (cmd != 11) in_urgent = 0;
10143 res = open_mailbox(&vms, vmu, cmd);
10144 if (res < 0)
10145 goto out;
10146 play_folder = cmd;
10147 cmd = 0;
10148 }
10149 if (useadsi)
10150 adsi_status2(chan, &vms);
10151
10152 if (!cmd) {
10153 cmd = vm_play_folder_name(chan, vms.vmbox);
10154 }
10155
10156 vms.starting = 1;
10157 vms.curmsg = 0;
10158 break;
10159 case '3':
10160 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10161 cmd = 0;
10162 vms.repeats = 0;
10163 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10164 switch (cmd) {
10165 case '1':
10166 if (vms.lastmsg > -1 && !vms.starting) {
10167 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10168 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10169 res = cmd;
10170 goto out;
10171 }
10172 } else {
10173 cmd = ast_play_and_wait(chan, "vm-sorry");
10174 }
10175 cmd = 't';
10176 break;
10177 case '2':
10178 if (!vms.starting)
10179 ast_verb(3, "Callback Requested\n");
10180 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10181 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10182 if (cmd == 9) {
10183 silentexit = 1;
10184 goto out;
10185 } else if (cmd == ERROR_LOCK_PATH) {
10186 res = cmd;
10187 goto out;
10188 }
10189 } else {
10190 cmd = ast_play_and_wait(chan, "vm-sorry");
10191 }
10192 cmd = 't';
10193 break;
10194 case '3':
10195 if (vms.lastmsg > -1 && !vms.starting) {
10196 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10197 if (cmd == ERROR_LOCK_PATH) {
10198 res = cmd;
10199 goto out;
10200 }
10201 } else {
10202 cmd = ast_play_and_wait(chan, "vm-sorry");
10203 }
10204 cmd = 't';
10205 break;
10206 case '4':
10207 if (!ast_strlen_zero(vmu->dialout)) {
10208 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10209 if (cmd == 9) {
10210 silentexit = 1;
10211 goto out;
10212 }
10213 } else {
10214 cmd = ast_play_and_wait(chan, "vm-sorry");
10215 }
10216 cmd = 't';
10217 break;
10218
10219 case '5':
10220 if (ast_test_flag(vmu, VM_SVMAIL)) {
10221 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10222 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10223 res = cmd;
10224 goto out;
10225 }
10226 } else {
10227 cmd = ast_play_and_wait(chan, "vm-sorry");
10228 }
10229 cmd = 't';
10230 break;
10231
10232 case '*':
10233 cmd = 't';
10234 break;
10235
10236 default:
10237 cmd = 0;
10238 if (!vms.starting) {
10239 cmd = ast_play_and_wait(chan, "vm-toreply");
10240 }
10241 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10242 cmd = ast_play_and_wait(chan, "vm-tocallback");
10243 }
10244 if (!cmd && !vms.starting) {
10245 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10246 }
10247 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10248 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10249 }
10250 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10251 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10252 }
10253 if (!cmd) {
10254 cmd = ast_play_and_wait(chan, "vm-starmain");
10255 }
10256 if (!cmd) {
10257 cmd = ast_waitfordigit(chan, 6000);
10258 }
10259 if (!cmd) {
10260 vms.repeats++;
10261 }
10262 if (vms.repeats > 3) {
10263 cmd = 't';
10264 }
10265 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10266 }
10267 }
10268 if (cmd == 't') {
10269 cmd = 0;
10270 vms.repeats = 0;
10271 }
10272 break;
10273 case '4':
10274 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10275 if (vms.curmsg > 0) {
10276 vms.curmsg--;
10277 cmd = play_message(chan, vmu, &vms);
10278 } else {
10279
10280
10281
10282
10283 if (in_urgent == 0 && vms.urgentmessages > 0) {
10284
10285 in_urgent = 1;
10286 res = close_mailbox(&vms, vmu);
10287 if (res == ERROR_LOCK_PATH)
10288 goto out;
10289 res = open_mailbox(&vms, vmu, 11);
10290 if (res < 0)
10291 goto out;
10292 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10293 vms.curmsg = vms.lastmsg;
10294 if (vms.lastmsg < 0) {
10295 cmd = ast_play_and_wait(chan, "vm-nomore");
10296 }
10297 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10298 vms.curmsg = vms.lastmsg;
10299 cmd = play_message(chan, vmu, &vms);
10300 } else {
10301 cmd = ast_play_and_wait(chan, "vm-nomore");
10302 }
10303 }
10304 break;
10305 case '6':
10306 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10307 if (vms.curmsg < vms.lastmsg) {
10308 vms.curmsg++;
10309 cmd = play_message(chan, vmu, &vms);
10310 } else {
10311 if (in_urgent && vms.newmessages > 0) {
10312
10313
10314
10315
10316 in_urgent = 0;
10317 res = close_mailbox(&vms, vmu);
10318 if (res == ERROR_LOCK_PATH)
10319 goto out;
10320 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10321 if (res < 0)
10322 goto out;
10323 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10324 vms.curmsg = -1;
10325 if (vms.lastmsg < 0) {
10326 cmd = ast_play_and_wait(chan, "vm-nomore");
10327 }
10328 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10329 vms.curmsg = 0;
10330 cmd = play_message(chan, vmu, &vms);
10331 } else {
10332 cmd = ast_play_and_wait(chan, "vm-nomore");
10333 }
10334 }
10335 break;
10336 case '7':
10337 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10338 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10339 if (useadsi)
10340 adsi_delete(chan, &vms);
10341 if (vms.deleted[vms.curmsg]) {
10342 if (play_folder == 0) {
10343 if (in_urgent) {
10344 vms.urgentmessages--;
10345 } else {
10346 vms.newmessages--;
10347 }
10348 }
10349 else if (play_folder == 1)
10350 vms.oldmessages--;
10351 cmd = ast_play_and_wait(chan, "vm-deleted");
10352 } else {
10353 if (play_folder == 0) {
10354 if (in_urgent) {
10355 vms.urgentmessages++;
10356 } else {
10357 vms.newmessages++;
10358 }
10359 }
10360 else if (play_folder == 1)
10361 vms.oldmessages++;
10362 cmd = ast_play_and_wait(chan, "vm-undeleted");
10363 }
10364 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10365 if (vms.curmsg < vms.lastmsg) {
10366 vms.curmsg++;
10367 cmd = play_message(chan, vmu, &vms);
10368 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10369 vms.curmsg = 0;
10370 cmd = play_message(chan, vmu, &vms);
10371 } else {
10372
10373
10374
10375
10376 if (in_urgent == 1) {
10377
10378 in_urgent = 0;
10379 res = close_mailbox(&vms, vmu);
10380 if (res == ERROR_LOCK_PATH)
10381 goto out;
10382 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10383 if (res < 0)
10384 goto out;
10385 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10386 vms.curmsg = -1;
10387 if (vms.lastmsg < 0) {
10388 cmd = ast_play_and_wait(chan, "vm-nomore");
10389 }
10390 } else {
10391 cmd = ast_play_and_wait(chan, "vm-nomore");
10392 }
10393 }
10394 }
10395 } else
10396 cmd = 0;
10397 #ifdef IMAP_STORAGE
10398 deleted = 1;
10399 #endif
10400 break;
10401
10402 case '8':
10403 if (vms.lastmsg > -1) {
10404 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10405 if (cmd == ERROR_LOCK_PATH) {
10406 res = cmd;
10407 goto out;
10408 }
10409 } else {
10410
10411
10412
10413
10414 if (in_urgent == 1 && vms.newmessages > 0) {
10415
10416 in_urgent = 0;
10417 res = close_mailbox(&vms, vmu);
10418 if (res == ERROR_LOCK_PATH)
10419 goto out;
10420 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10421 if (res < 0)
10422 goto out;
10423 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10424 vms.curmsg = -1;
10425 if (vms.lastmsg < 0) {
10426 cmd = ast_play_and_wait(chan, "vm-nomore");
10427 }
10428 } else {
10429 cmd = ast_play_and_wait(chan, "vm-nomore");
10430 }
10431 }
10432 break;
10433 case '9':
10434 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10435 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10436
10437 cmd = 0;
10438 break;
10439 }
10440 if (useadsi)
10441 adsi_folders(chan, 1, "Save to folder...");
10442 cmd = get_folder2(chan, "vm-savefolder", 1);
10443 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10444 box = 0;
10445 if (cmd == '#') {
10446 cmd = 0;
10447 break;
10448 } else if (cmd > 0) {
10449 box = cmd = cmd - '0';
10450 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10451 if (cmd == ERROR_LOCK_PATH) {
10452 res = cmd;
10453 goto out;
10454 #ifndef IMAP_STORAGE
10455 } else if (!cmd) {
10456 vms.deleted[vms.curmsg] = 1;
10457 #endif
10458 } else {
10459 vms.deleted[vms.curmsg] = 0;
10460 vms.heard[vms.curmsg] = 0;
10461 }
10462 }
10463 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10464 if (useadsi)
10465 adsi_message(chan, &vms);
10466 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10467 if (!cmd) {
10468 cmd = ast_play_and_wait(chan, "vm-message");
10469 if (!cmd)
10470 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10471 if (!cmd)
10472 cmd = ast_play_and_wait(chan, "vm-savedto");
10473 if (!cmd)
10474 cmd = vm_play_folder_name(chan, vms.fn);
10475 } else {
10476 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10477 }
10478 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10479 if (vms.curmsg < vms.lastmsg) {
10480 vms.curmsg++;
10481 cmd = play_message(chan, vmu, &vms);
10482 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10483 vms.curmsg = 0;
10484 cmd = play_message(chan, vmu, &vms);
10485 } else {
10486
10487
10488
10489
10490 if (in_urgent == 1 && vms.newmessages > 0) {
10491
10492 in_urgent = 0;
10493 res = close_mailbox(&vms, vmu);
10494 if (res == ERROR_LOCK_PATH)
10495 goto out;
10496 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10497 if (res < 0)
10498 goto out;
10499 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10500 vms.curmsg = -1;
10501 if (vms.lastmsg < 0) {
10502 cmd = ast_play_and_wait(chan, "vm-nomore");
10503 }
10504 } else {
10505 cmd = ast_play_and_wait(chan, "vm-nomore");
10506 }
10507 }
10508 }
10509 break;
10510 case '*':
10511 if (!vms.starting) {
10512 cmd = ast_play_and_wait(chan, "vm-onefor");
10513 if (!strncasecmp(chan->language, "he", 2)) {
10514 cmd = ast_play_and_wait(chan, "vm-for");
10515 }
10516 if (!cmd)
10517 cmd = vm_play_folder_name(chan, vms.vmbox);
10518 if (!cmd)
10519 cmd = ast_play_and_wait(chan, "vm-opts");
10520 if (!cmd)
10521 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10522 } else
10523 cmd = 0;
10524 break;
10525 case '0':
10526 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10527 if (useadsi)
10528 adsi_status(chan, &vms);
10529 break;
10530 default:
10531 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10532 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10533 break;
10534 }
10535 }
10536 if ((cmd == 't') || (cmd == '#')) {
10537
10538 res = 0;
10539 } else {
10540
10541 res = -1;
10542 }
10543
10544 out:
10545 if (res > -1) {
10546 ast_stopstream(chan);
10547 adsi_goodbye(chan);
10548 if (valid && res != OPERATOR_EXIT) {
10549 if (silentexit)
10550 res = ast_play_and_wait(chan, "vm-dialout");
10551 else
10552 res = ast_play_and_wait(chan, "vm-goodbye");
10553 }
10554 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10555 res = 0;
10556 }
10557 if (useadsi)
10558 ast_adsi_unload_session(chan);
10559 }
10560 if (vmu)
10561 close_mailbox(&vms, vmu);
10562 if (valid) {
10563 int new = 0, old = 0, urgent = 0;
10564 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10565 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10566
10567 run_externnotify(vmu->context, vmu->mailbox, NULL);
10568 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10569 queue_mwi_event(ext_context, urgent, new, old);
10570 }
10571 #ifdef IMAP_STORAGE
10572
10573 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10574 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10575 ast_mutex_lock(&vms.lock);
10576 #ifdef HAVE_IMAP_TK2006
10577 if (LEVELUIDPLUS (vms.mailstream)) {
10578 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10579 } else
10580 #endif
10581 mail_expunge(vms.mailstream);
10582 ast_mutex_unlock(&vms.lock);
10583 }
10584
10585
10586 if (vmu) {
10587 vmstate_delete(&vms);
10588 }
10589 #endif
10590 if (vmu)
10591 free_user(vmu);
10592
10593 #ifdef IMAP_STORAGE
10594 pthread_setspecific(ts_vmstate.key, NULL);
10595 #endif
10596 return res;
10597 }
10598
10599 static int vm_exec(struct ast_channel *chan, const char *data)
10600 {
10601 int res = 0;
10602 char *tmp;
10603 struct leave_vm_options leave_options;
10604 struct ast_flags flags = { 0 };
10605 char *opts[OPT_ARG_ARRAY_SIZE];
10606 AST_DECLARE_APP_ARGS(args,
10607 AST_APP_ARG(argv0);
10608 AST_APP_ARG(argv1);
10609 );
10610
10611 memset(&leave_options, 0, sizeof(leave_options));
10612
10613 if (chan->_state != AST_STATE_UP)
10614 ast_answer(chan);
10615
10616 if (!ast_strlen_zero(data)) {
10617 tmp = ast_strdupa(data);
10618 AST_STANDARD_APP_ARGS(args, tmp);
10619 if (args.argc == 2) {
10620 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10621 return -1;
10622 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10623 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10624 int gain;
10625
10626 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10627 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10628 return -1;
10629 } else {
10630 leave_options.record_gain = (signed char) gain;
10631 }
10632 }
10633 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10634 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10635 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10636 }
10637 }
10638 } else {
10639 char temp[256];
10640 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10641 if (res < 0)
10642 return res;
10643 if (ast_strlen_zero(temp))
10644 return 0;
10645 args.argv0 = ast_strdupa(temp);
10646 }
10647
10648 res = leave_voicemail(chan, args.argv0, &leave_options);
10649 if (res == 't') {
10650 ast_play_and_wait(chan, "vm-goodbye");
10651 res = 0;
10652 }
10653
10654 if (res == OPERATOR_EXIT) {
10655 res = 0;
10656 }
10657
10658 if (res == ERROR_LOCK_PATH) {
10659 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10660 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10661 res = 0;
10662 }
10663
10664 return res;
10665 }
10666
10667 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10668 {
10669 struct ast_vm_user *vmu;
10670
10671 if (!ast_strlen_zero(box) && box[0] == '*') {
10672 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10673 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10674 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10675 "\n\tand will be ignored.\n", box, context);
10676 return NULL;
10677 }
10678
10679 AST_LIST_TRAVERSE(&users, vmu, list) {
10680 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10681 if (strcasecmp(vmu->context, context)) {
10682 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10683 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10684 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10685 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10686 }
10687 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10688 return NULL;
10689 }
10690 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10691 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10692 return NULL;
10693 }
10694 }
10695
10696 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10697 return NULL;
10698
10699 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10700 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10701
10702 AST_LIST_INSERT_TAIL(&users, vmu, list);
10703
10704 return vmu;
10705 }
10706
10707 static int append_mailbox(const char *context, const char *box, const char *data)
10708 {
10709
10710 char *tmp;
10711 char *stringp;
10712 char *s;
10713 struct ast_vm_user *vmu;
10714 char *mailbox_full;
10715 int new = 0, old = 0, urgent = 0;
10716 char secretfn[PATH_MAX] = "";
10717
10718 tmp = ast_strdupa(data);
10719
10720 if (!(vmu = find_or_create(context, box)))
10721 return -1;
10722
10723 populate_defaults(vmu);
10724
10725 stringp = tmp;
10726 if ((s = strsep(&stringp, ","))) {
10727 if (!ast_strlen_zero(s) && s[0] == '*') {
10728 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10729 "\n\tmust be reset in voicemail.conf.\n", box);
10730 }
10731
10732 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10733 }
10734 if (stringp && (s = strsep(&stringp, ","))) {
10735 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10736 }
10737 if (stringp && (s = strsep(&stringp, ","))) {
10738 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10739 }
10740 if (stringp && (s = strsep(&stringp, ","))) {
10741 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10742 }
10743 if (stringp && (s = strsep(&stringp, ","))) {
10744 apply_options(vmu, s);
10745 }
10746
10747 switch (vmu->passwordlocation) {
10748 case OPT_PWLOC_SPOOLDIR:
10749 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10750 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10751 }
10752
10753 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
10754 strcpy(mailbox_full, box);
10755 strcat(mailbox_full, "@");
10756 strcat(mailbox_full, context);
10757
10758 inboxcount2(mailbox_full, &urgent, &new, &old);
10759 queue_mwi_event(mailbox_full, urgent, new, old);
10760
10761 return 0;
10762 }
10763
10764 AST_TEST_DEFINE(test_voicemail_vmuser)
10765 {
10766 int res = 0;
10767 struct ast_vm_user *vmu;
10768
10769 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10770 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10771 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10772 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10773 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10774 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10775 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10776 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10777 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10778 #ifdef IMAP_STORAGE
10779 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10780 "imapfolder=INBOX|imapvmshareid=6000";
10781 #endif
10782
10783 switch (cmd) {
10784 case TEST_INIT:
10785 info->name = "vmuser";
10786 info->category = "/apps/app_voicemail/";
10787 info->summary = "Vmuser unit test";
10788 info->description =
10789 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10790 return AST_TEST_NOT_RUN;
10791 case TEST_EXECUTE:
10792 break;
10793 }
10794
10795 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10796 return AST_TEST_NOT_RUN;
10797 }
10798 populate_defaults(vmu);
10799 ast_set_flag(vmu, VM_ALLOCED);
10800
10801 apply_options(vmu, options_string);
10802
10803 if (!ast_test_flag(vmu, VM_ATTACH)) {
10804 ast_test_status_update(test, "Parse failure for attach option\n");
10805 res = 1;
10806 }
10807 if (strcasecmp(vmu->attachfmt, "wav49")) {
10808 ast_test_status_update(test, "Parse failure for attachftm option\n");
10809 res = 1;
10810 }
10811 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10812 ast_test_status_update(test, "Parse failure for serveremail option\n");
10813 res = 1;
10814 }
10815 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10816 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10817 res = 1;
10818 }
10819 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10820 ast_test_status_update(test, "Parse failure for emailbody option\n");
10821 res = 1;
10822 }
10823 if (strcasecmp(vmu->zonetag, "central")) {
10824 ast_test_status_update(test, "Parse failure for tz option\n");
10825 res = 1;
10826 }
10827 if (!ast_test_flag(vmu, VM_DELETE)) {
10828 ast_test_status_update(test, "Parse failure for delete option\n");
10829 res = 1;
10830 }
10831 if (!ast_test_flag(vmu, VM_SAYCID)) {
10832 ast_test_status_update(test, "Parse failure for saycid option\n");
10833 res = 1;
10834 }
10835 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10836 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10837 res = 1;
10838 }
10839 if (!ast_test_flag(vmu, VM_REVIEW)) {
10840 ast_test_status_update(test, "Parse failure for review option\n");
10841 res = 1;
10842 }
10843 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10844 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10845 res = 1;
10846 }
10847 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10848 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10849 res = 1;
10850 }
10851 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10852 ast_test_status_update(test, "Parse failure for operator option\n");
10853 res = 1;
10854 }
10855 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10856 ast_test_status_update(test, "Parse failure for envelope option\n");
10857 res = 1;
10858 }
10859 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10860 ast_test_status_update(test, "Parse failure for moveheard option\n");
10861 res = 1;
10862 }
10863 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10864 ast_test_status_update(test, "Parse failure for sayduration option\n");
10865 res = 1;
10866 }
10867 if (vmu->saydurationm != 5) {
10868 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10869 res = 1;
10870 }
10871 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10872 ast_test_status_update(test, "Parse failure for forcename option\n");
10873 res = 1;
10874 }
10875 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10876 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10877 res = 1;
10878 }
10879 if (strcasecmp(vmu->callback, "somecontext")) {
10880 ast_test_status_update(test, "Parse failure for callbacks option\n");
10881 res = 1;
10882 }
10883 if (strcasecmp(vmu->dialout, "somecontext2")) {
10884 ast_test_status_update(test, "Parse failure for dialout option\n");
10885 res = 1;
10886 }
10887 if (strcasecmp(vmu->exit, "somecontext3")) {
10888 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10889 res = 1;
10890 }
10891 if (vmu->minsecs != 10) {
10892 ast_test_status_update(test, "Parse failure for minsecs option\n");
10893 res = 1;
10894 }
10895 if (vmu->maxsecs != 100) {
10896 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10897 res = 1;
10898 }
10899 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10900 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10901 res = 1;
10902 }
10903 if (vmu->maxdeletedmsg != 50) {
10904 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10905 res = 1;
10906 }
10907 if (vmu->volgain != 1.3) {
10908 ast_test_status_update(test, "Parse failure for volgain option\n");
10909 res = 1;
10910 }
10911 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10912 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10913 res = 1;
10914 }
10915 #ifdef IMAP_STORAGE
10916 apply_options(vmu, option_string2);
10917
10918 if (strcasecmp(vmu->imapuser, "imapuser")) {
10919 ast_test_status_update(test, "Parse failure for imapuser option\n");
10920 res = 1;
10921 }
10922 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10923 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10924 res = 1;
10925 }
10926 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10927 ast_test_status_update(test, "Parse failure for imapfolder option\n");
10928 res = 1;
10929 }
10930 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10931 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10932 res = 1;
10933 }
10934 #endif
10935
10936 free_user(vmu);
10937 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10938 }
10939
10940 static int vm_box_exists(struct ast_channel *chan, const char *data)
10941 {
10942 struct ast_vm_user svm;
10943 char *context, *box;
10944 AST_DECLARE_APP_ARGS(args,
10945 AST_APP_ARG(mbox);
10946 AST_APP_ARG(options);
10947 );
10948 static int dep_warning = 0;
10949
10950 if (ast_strlen_zero(data)) {
10951 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10952 return -1;
10953 }
10954
10955 if (!dep_warning) {
10956 dep_warning = 1;
10957 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10958 }
10959
10960 box = ast_strdupa(data);
10961
10962 AST_STANDARD_APP_ARGS(args, box);
10963
10964 if (args.options) {
10965 }
10966
10967 if ((context = strchr(args.mbox, '@'))) {
10968 *context = '\0';
10969 context++;
10970 }
10971
10972 if (find_user(&svm, context, args.mbox)) {
10973 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
10974 } else
10975 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
10976
10977 return 0;
10978 }
10979
10980 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
10981 {
10982 struct ast_vm_user svm;
10983 AST_DECLARE_APP_ARGS(arg,
10984 AST_APP_ARG(mbox);
10985 AST_APP_ARG(context);
10986 );
10987
10988 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
10989
10990 if (ast_strlen_zero(arg.mbox)) {
10991 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
10992 return -1;
10993 }
10994
10995 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
10996 return 0;
10997 }
10998
10999 static struct ast_custom_function mailbox_exists_acf = {
11000 .name = "MAILBOX_EXISTS",
11001 .read = acf_mailbox_exists,
11002 };
11003
11004 static int vmauthenticate(struct ast_channel *chan, const char *data)
11005 {
11006 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11007 struct ast_vm_user vmus;
11008 char *options = NULL;
11009 int silent = 0, skipuser = 0;
11010 int res = -1;
11011
11012 if (data) {
11013 s = ast_strdupa(data);
11014 user = strsep(&s, ",");
11015 options = strsep(&s, ",");
11016 if (user) {
11017 s = user;
11018 user = strsep(&s, "@");
11019 context = strsep(&s, "");
11020 if (!ast_strlen_zero(user))
11021 skipuser++;
11022 ast_copy_string(mailbox, user, sizeof(mailbox));
11023 }
11024 }
11025
11026 if (options) {
11027 silent = (strchr(options, 's')) != NULL;
11028 }
11029
11030 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11031 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11032 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11033 ast_play_and_wait(chan, "auth-thankyou");
11034 res = 0;
11035 } else if (mailbox[0] == '*') {
11036
11037 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11038 res = 0;
11039 }
11040 }
11041
11042 return res;
11043 }
11044
11045 static char *show_users_realtime(int fd, const char *context)
11046 {
11047 struct ast_config *cfg;
11048 const char *cat = NULL;
11049
11050 if (!(cfg = ast_load_realtime_multientry("voicemail",
11051 "context", context, SENTINEL))) {
11052 return CLI_FAILURE;
11053 }
11054
11055 ast_cli(fd,
11056 "\n"
11057 "=============================================================\n"
11058 "=== Configured Voicemail Users ==============================\n"
11059 "=============================================================\n"
11060 "===\n");
11061
11062 while ((cat = ast_category_browse(cfg, cat))) {
11063 struct ast_variable *var = NULL;
11064 ast_cli(fd,
11065 "=== Mailbox ...\n"
11066 "===\n");
11067 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11068 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11069 ast_cli(fd,
11070 "===\n"
11071 "=== ---------------------------------------------------------\n"
11072 "===\n");
11073 }
11074
11075 ast_cli(fd,
11076 "=============================================================\n"
11077 "\n");
11078
11079 ast_config_destroy(cfg);
11080
11081 return CLI_SUCCESS;
11082 }
11083
11084 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11085 {
11086 int which = 0;
11087 int wordlen;
11088 struct ast_vm_user *vmu;
11089 const char *context = "";
11090
11091
11092 if (pos > 4)
11093 return NULL;
11094 if (pos == 3)
11095 return (state == 0) ? ast_strdup("for") : NULL;
11096 wordlen = strlen(word);
11097 AST_LIST_TRAVERSE(&users, vmu, list) {
11098 if (!strncasecmp(word, vmu->context, wordlen)) {
11099 if (context && strcmp(context, vmu->context) && ++which > state)
11100 return ast_strdup(vmu->context);
11101
11102 context = vmu->context;
11103 }
11104 }
11105 return NULL;
11106 }
11107
11108
11109 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11110 {
11111 struct ast_vm_user *vmu;
11112 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11113 const char *context = NULL;
11114 int users_counter = 0;
11115
11116 switch (cmd) {
11117 case CLI_INIT:
11118 e->command = "voicemail show users";
11119 e->usage =
11120 "Usage: voicemail show users [for <context>]\n"
11121 " Lists all mailboxes currently set up\n";
11122 return NULL;
11123 case CLI_GENERATE:
11124 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11125 }
11126
11127 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11128 return CLI_SHOWUSAGE;
11129 if (a->argc == 5) {
11130 if (strcmp(a->argv[3],"for"))
11131 return CLI_SHOWUSAGE;
11132 context = a->argv[4];
11133 }
11134
11135 if (ast_check_realtime("voicemail")) {
11136 if (!context) {
11137 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11138 return CLI_SHOWUSAGE;
11139 }
11140 return show_users_realtime(a->fd, context);
11141 }
11142
11143 AST_LIST_LOCK(&users);
11144 if (AST_LIST_EMPTY(&users)) {
11145 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11146 AST_LIST_UNLOCK(&users);
11147 return CLI_FAILURE;
11148 }
11149 if (!context) {
11150 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11151 } else {
11152 int count = 0;
11153 AST_LIST_TRAVERSE(&users, vmu, list) {
11154 if (!strcmp(context, vmu->context)) {
11155 count++;
11156 break;
11157 }
11158 }
11159 if (count) {
11160 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11161 } else {
11162 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11163 AST_LIST_UNLOCK(&users);
11164 return CLI_FAILURE;
11165 }
11166 }
11167 AST_LIST_TRAVERSE(&users, vmu, list) {
11168 int newmsgs = 0, oldmsgs = 0;
11169 char count[12], tmp[256] = "";
11170
11171 if (!context || !strcmp(context, vmu->context)) {
11172 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11173 inboxcount(tmp, &newmsgs, &oldmsgs);
11174 snprintf(count, sizeof(count), "%d", newmsgs);
11175 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11176 users_counter++;
11177 }
11178 }
11179 AST_LIST_UNLOCK(&users);
11180 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11181 return CLI_SUCCESS;
11182 }
11183
11184
11185 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11186 {
11187 struct vm_zone *zone;
11188 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11189 char *res = CLI_SUCCESS;
11190
11191 switch (cmd) {
11192 case CLI_INIT:
11193 e->command = "voicemail show zones";
11194 e->usage =
11195 "Usage: voicemail show zones\n"
11196 " Lists zone message formats\n";
11197 return NULL;
11198 case CLI_GENERATE:
11199 return NULL;
11200 }
11201
11202 if (a->argc != 3)
11203 return CLI_SHOWUSAGE;
11204
11205 AST_LIST_LOCK(&zones);
11206 if (!AST_LIST_EMPTY(&zones)) {
11207 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11208 AST_LIST_TRAVERSE(&zones, zone, list) {
11209 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11210 }
11211 } else {
11212 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11213 res = CLI_FAILURE;
11214 }
11215 AST_LIST_UNLOCK(&zones);
11216
11217 return res;
11218 }
11219
11220
11221 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11222 {
11223 switch (cmd) {
11224 case CLI_INIT:
11225 e->command = "voicemail reload";
11226 e->usage =
11227 "Usage: voicemail reload\n"
11228 " Reload voicemail configuration\n";
11229 return NULL;
11230 case CLI_GENERATE:
11231 return NULL;
11232 }
11233
11234 if (a->argc != 2)
11235 return CLI_SHOWUSAGE;
11236
11237 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11238 load_config(1);
11239
11240 return CLI_SUCCESS;
11241 }
11242
11243 static struct ast_cli_entry cli_voicemail[] = {
11244 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11245 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11246 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11247 };
11248
11249 #ifdef IMAP_STORAGE
11250 #define DATA_EXPORT_VM_USERS(USER) \
11251 USER(ast_vm_user, context, AST_DATA_STRING) \
11252 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11253 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11254 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11255 USER(ast_vm_user, email, AST_DATA_STRING) \
11256 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11257 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11258 USER(ast_vm_user, pager, AST_DATA_STRING) \
11259 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11260 USER(ast_vm_user, language, AST_DATA_STRING) \
11261 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11262 USER(ast_vm_user, callback, AST_DATA_STRING) \
11263 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11264 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11265 USER(ast_vm_user, exit, AST_DATA_STRING) \
11266 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11267 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11268 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11269 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11270 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11271 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11272 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11273 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11274 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11275 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11276 #else
11277 #define DATA_EXPORT_VM_USERS(USER) \
11278 USER(ast_vm_user, context, AST_DATA_STRING) \
11279 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11280 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11281 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11282 USER(ast_vm_user, email, AST_DATA_STRING) \
11283 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11284 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11285 USER(ast_vm_user, pager, AST_DATA_STRING) \
11286 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11287 USER(ast_vm_user, language, AST_DATA_STRING) \
11288 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11289 USER(ast_vm_user, callback, AST_DATA_STRING) \
11290 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11291 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11292 USER(ast_vm_user, exit, AST_DATA_STRING) \
11293 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11294 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11295 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11296 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11297 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11298 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11299 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11300 #endif
11301
11302 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11303
11304 #define DATA_EXPORT_VM_ZONES(ZONE) \
11305 ZONE(vm_zone, name, AST_DATA_STRING) \
11306 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11307 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11308
11309 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11310
11311
11312
11313
11314
11315
11316
11317
11318 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11319 struct ast_data *data_root, struct ast_vm_user *user)
11320 {
11321 struct ast_data *data_user, *data_zone;
11322 struct ast_data *data_state;
11323 struct vm_zone *zone = NULL;
11324 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11325 char ext_context[256] = "";
11326
11327 data_user = ast_data_add_node(data_root, "user");
11328 if (!data_user) {
11329 return -1;
11330 }
11331
11332 ast_data_add_structure(ast_vm_user, data_user, user);
11333
11334 AST_LIST_LOCK(&zones);
11335 AST_LIST_TRAVERSE(&zones, zone, list) {
11336 if (!strcmp(zone->name, user->zonetag)) {
11337 break;
11338 }
11339 }
11340 AST_LIST_UNLOCK(&zones);
11341
11342
11343 data_state = ast_data_add_node(data_user, "state");
11344 if (!data_state) {
11345 return -1;
11346 }
11347 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11348 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11349 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11350 ast_data_add_int(data_state, "newmsg", newmsg);
11351 ast_data_add_int(data_state, "oldmsg", oldmsg);
11352
11353 if (zone) {
11354 data_zone = ast_data_add_node(data_user, "zone");
11355 ast_data_add_structure(vm_zone, data_zone, zone);
11356 }
11357
11358 if (!ast_data_search_match(search, data_user)) {
11359 ast_data_remove_node(data_root, data_user);
11360 }
11361
11362 return 0;
11363 }
11364
11365 static int vm_users_data_provider_get(const struct ast_data_search *search,
11366 struct ast_data *data_root)
11367 {
11368 struct ast_vm_user *user;
11369
11370 AST_LIST_LOCK(&users);
11371 AST_LIST_TRAVERSE(&users, user, list) {
11372 vm_users_data_provider_get_helper(search, data_root, user);
11373 }
11374 AST_LIST_UNLOCK(&users);
11375
11376 return 0;
11377 }
11378
11379 static const struct ast_data_handler vm_users_data_provider = {
11380 .version = AST_DATA_HANDLER_VERSION,
11381 .get = vm_users_data_provider_get
11382 };
11383
11384 static const struct ast_data_entry vm_data_providers[] = {
11385 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11386 };
11387
11388 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11389 {
11390 int new = 0, old = 0, urgent = 0;
11391
11392 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11393
11394 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11395 mwi_sub->old_urgent = urgent;
11396 mwi_sub->old_new = new;
11397 mwi_sub->old_old = old;
11398 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11399 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11400 }
11401 }
11402
11403 static void poll_subscribed_mailboxes(void)
11404 {
11405 struct mwi_sub *mwi_sub;
11406
11407 AST_RWLIST_RDLOCK(&mwi_subs);
11408 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11409 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11410 poll_subscribed_mailbox(mwi_sub);
11411 }
11412 }
11413 AST_RWLIST_UNLOCK(&mwi_subs);
11414 }
11415
11416 static void *mb_poll_thread(void *data)
11417 {
11418 while (poll_thread_run) {
11419 struct timespec ts = { 0, };
11420 struct timeval wait;
11421
11422 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11423 ts.tv_sec = wait.tv_sec;
11424 ts.tv_nsec = wait.tv_usec * 1000;
11425
11426 ast_mutex_lock(&poll_lock);
11427 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11428 ast_mutex_unlock(&poll_lock);
11429
11430 if (!poll_thread_run)
11431 break;
11432
11433 poll_subscribed_mailboxes();
11434 }
11435
11436 return NULL;
11437 }
11438
11439 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11440 {
11441 ast_free(mwi_sub);
11442 }
11443
11444 static int handle_unsubscribe(void *datap)
11445 {
11446 struct mwi_sub *mwi_sub;
11447 uint32_t *uniqueid = datap;
11448
11449 AST_RWLIST_WRLOCK(&mwi_subs);
11450 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11451 if (mwi_sub->uniqueid == *uniqueid) {
11452 AST_LIST_REMOVE_CURRENT(entry);
11453 break;
11454 }
11455 }
11456 AST_RWLIST_TRAVERSE_SAFE_END
11457 AST_RWLIST_UNLOCK(&mwi_subs);
11458
11459 if (mwi_sub)
11460 mwi_sub_destroy(mwi_sub);
11461
11462 ast_free(uniqueid);
11463 return 0;
11464 }
11465
11466 static int handle_subscribe(void *datap)
11467 {
11468 unsigned int len;
11469 struct mwi_sub *mwi_sub;
11470 struct mwi_sub_task *p = datap;
11471
11472 len = sizeof(*mwi_sub);
11473 if (!ast_strlen_zero(p->mailbox))
11474 len += strlen(p->mailbox);
11475
11476 if (!ast_strlen_zero(p->context))
11477 len += strlen(p->context) + 1;
11478
11479 if (!(mwi_sub = ast_calloc(1, len)))
11480 return -1;
11481
11482 mwi_sub->uniqueid = p->uniqueid;
11483 if (!ast_strlen_zero(p->mailbox))
11484 strcpy(mwi_sub->mailbox, p->mailbox);
11485
11486 if (!ast_strlen_zero(p->context)) {
11487 strcat(mwi_sub->mailbox, "@");
11488 strcat(mwi_sub->mailbox, p->context);
11489 }
11490
11491 AST_RWLIST_WRLOCK(&mwi_subs);
11492 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11493 AST_RWLIST_UNLOCK(&mwi_subs);
11494 ast_free((void *) p->mailbox);
11495 ast_free((void *) p->context);
11496 ast_free(p);
11497 poll_subscribed_mailbox(mwi_sub);
11498 return 0;
11499 }
11500
11501 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11502 {
11503 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11504
11505 if (!uniqueid) {
11506 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11507 return;
11508 }
11509
11510 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11511 ast_free(uniqueid);
11512 return;
11513 }
11514
11515 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11516 ast_free(uniqueid);
11517 return;
11518 }
11519
11520 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11521 *uniqueid = u;
11522 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11523 ast_free(uniqueid);
11524 }
11525 }
11526
11527 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11528 {
11529 struct mwi_sub_task *mwist;
11530
11531 if (ast_event_get_type(event) != AST_EVENT_SUB)
11532 return;
11533
11534 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11535 return;
11536
11537 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11538 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11539 return;
11540 }
11541 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11542 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11543 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11544
11545 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11546 ast_free(mwist);
11547 }
11548 }
11549
11550 static void start_poll_thread(void)
11551 {
11552 int errcode;
11553 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11554 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11555 AST_EVENT_IE_END);
11556
11557 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11558 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11559 AST_EVENT_IE_END);
11560
11561 if (mwi_sub_sub)
11562 ast_event_report_subs(mwi_sub_sub);
11563
11564 poll_thread_run = 1;
11565
11566 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11567 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11568 }
11569 }
11570
11571 static void stop_poll_thread(void)
11572 {
11573 poll_thread_run = 0;
11574
11575 if (mwi_sub_sub) {
11576 ast_event_unsubscribe(mwi_sub_sub);
11577 mwi_sub_sub = NULL;
11578 }
11579
11580 if (mwi_unsub_sub) {
11581 ast_event_unsubscribe(mwi_unsub_sub);
11582 mwi_unsub_sub = NULL;
11583 }
11584
11585 ast_mutex_lock(&poll_lock);
11586 ast_cond_signal(&poll_cond);
11587 ast_mutex_unlock(&poll_lock);
11588
11589 pthread_join(poll_thread, NULL);
11590
11591 poll_thread = AST_PTHREADT_NULL;
11592 }
11593
11594
11595 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11596 {
11597 struct ast_vm_user *vmu = NULL;
11598 const char *id = astman_get_header(m, "ActionID");
11599 char actionid[128] = "";
11600
11601 if (!ast_strlen_zero(id))
11602 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11603
11604 AST_LIST_LOCK(&users);
11605
11606 if (AST_LIST_EMPTY(&users)) {
11607 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11608 AST_LIST_UNLOCK(&users);
11609 return RESULT_SUCCESS;
11610 }
11611
11612 astman_send_ack(s, m, "Voicemail user list will follow");
11613
11614 AST_LIST_TRAVERSE(&users, vmu, list) {
11615 char dirname[256];
11616
11617 #ifdef IMAP_STORAGE
11618 int new, old;
11619 inboxcount(vmu->mailbox, &new, &old);
11620 #endif
11621
11622 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11623 astman_append(s,
11624 "%s"
11625 "Event: VoicemailUserEntry\r\n"
11626 "VMContext: %s\r\n"
11627 "VoiceMailbox: %s\r\n"
11628 "Fullname: %s\r\n"
11629 "Email: %s\r\n"
11630 "Pager: %s\r\n"
11631 "ServerEmail: %s\r\n"
11632 "MailCommand: %s\r\n"
11633 "Language: %s\r\n"
11634 "TimeZone: %s\r\n"
11635 "Callback: %s\r\n"
11636 "Dialout: %s\r\n"
11637 "UniqueID: %s\r\n"
11638 "ExitContext: %s\r\n"
11639 "SayDurationMinimum: %d\r\n"
11640 "SayEnvelope: %s\r\n"
11641 "SayCID: %s\r\n"
11642 "AttachMessage: %s\r\n"
11643 "AttachmentFormat: %s\r\n"
11644 "DeleteMessage: %s\r\n"
11645 "VolumeGain: %.2f\r\n"
11646 "CanReview: %s\r\n"
11647 "CallOperator: %s\r\n"
11648 "MaxMessageCount: %d\r\n"
11649 "MaxMessageLength: %d\r\n"
11650 "NewMessageCount: %d\r\n"
11651 #ifdef IMAP_STORAGE
11652 "OldMessageCount: %d\r\n"
11653 "IMAPUser: %s\r\n"
11654 #endif
11655 "\r\n",
11656 actionid,
11657 vmu->context,
11658 vmu->mailbox,
11659 vmu->fullname,
11660 vmu->email,
11661 vmu->pager,
11662 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
11663 mailcmd,
11664 vmu->language,
11665 vmu->zonetag,
11666 vmu->callback,
11667 vmu->dialout,
11668 vmu->uniqueid,
11669 vmu->exit,
11670 vmu->saydurationm,
11671 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11672 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11673 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11674 vmu->attachfmt,
11675 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11676 vmu->volgain,
11677 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11678 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11679 vmu->maxmsg,
11680 vmu->maxsecs,
11681 #ifdef IMAP_STORAGE
11682 new, old, vmu->imapuser
11683 #else
11684 count_messages(vmu, dirname)
11685 #endif
11686 );
11687 }
11688 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11689
11690 AST_LIST_UNLOCK(&users);
11691
11692 return RESULT_SUCCESS;
11693 }
11694
11695
11696 static void free_vm_users(void)
11697 {
11698 struct ast_vm_user *current;
11699 AST_LIST_LOCK(&users);
11700 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11701 ast_set_flag(current, VM_ALLOCED);
11702 free_user(current);
11703 }
11704 AST_LIST_UNLOCK(&users);
11705 }
11706
11707
11708 static void free_vm_zones(void)
11709 {
11710 struct vm_zone *zcur;
11711 AST_LIST_LOCK(&zones);
11712 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11713 free_zone(zcur);
11714 AST_LIST_UNLOCK(&zones);
11715 }
11716
11717 static const char *substitute_escapes(const char *value)
11718 {
11719 char *current;
11720
11721
11722 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11723
11724 ast_str_reset(str);
11725
11726
11727 for (current = (char *) value; *current; current++) {
11728 if (*current == '\\') {
11729 current++;
11730 if (!*current) {
11731 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11732 break;
11733 }
11734 switch (*current) {
11735 case '\\':
11736 ast_str_append(&str, 0, "\\");
11737 break;
11738 case 'r':
11739 ast_str_append(&str, 0, "\r");
11740 break;
11741 case 'n':
11742 #ifdef IMAP_STORAGE
11743 if (!str->used || str->str[str->used - 1] != '\r') {
11744 ast_str_append(&str, 0, "\r");
11745 }
11746 #endif
11747 ast_str_append(&str, 0, "\n");
11748 break;
11749 case 't':
11750 ast_str_append(&str, 0, "\t");
11751 break;
11752 default:
11753 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11754 break;
11755 }
11756 } else {
11757 ast_str_append(&str, 0, "%c", *current);
11758 }
11759 }
11760
11761 return ast_str_buffer(str);
11762 }
11763
11764 static int load_config(int reload)
11765 {
11766 struct ast_config *cfg, *ucfg;
11767 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11768 int res;
11769
11770 ast_unload_realtime("voicemail");
11771 ast_unload_realtime("voicemail_data");
11772
11773 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11774 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11775 return 0;
11776 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11777 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11778 ucfg = NULL;
11779 }
11780 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11781 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11782 ast_config_destroy(ucfg);
11783 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11784 return 0;
11785 }
11786 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11787 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11788 return 0;
11789 } else {
11790 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11791 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11792 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11793 ucfg = NULL;
11794 }
11795 }
11796
11797 res = actual_load_config(reload, cfg, ucfg);
11798
11799 ast_config_destroy(cfg);
11800 ast_config_destroy(ucfg);
11801
11802 return res;
11803 }
11804
11805 #ifdef TEST_FRAMEWORK
11806 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11807 {
11808 ast_unload_realtime("voicemail");
11809 ast_unload_realtime("voicemail_data");
11810 return actual_load_config(reload, cfg, ucfg);
11811 }
11812 #endif
11813
11814 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11815 {
11816 struct ast_vm_user *current;
11817 char *cat;
11818 struct ast_variable *var;
11819 const char *val;
11820 char *q, *stringp, *tmp;
11821 int x;
11822 unsigned int tmpadsi[4];
11823 char secretfn[PATH_MAX] = "";
11824
11825 #ifdef IMAP_STORAGE
11826 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11827 #endif
11828
11829 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11830 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11831 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11832 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11833 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11834
11835
11836 free_vm_users();
11837
11838
11839 free_vm_zones();
11840
11841 AST_LIST_LOCK(&users);
11842
11843 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11844 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11845
11846 if (cfg) {
11847
11848
11849 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11850 val = "default";
11851 ast_copy_string(userscontext, val, sizeof(userscontext));
11852
11853 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11854 val = "yes";
11855 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11856
11857 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11858 val = "no";
11859 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11860
11861 volgain = 0.0;
11862 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11863 sscanf(val, "%30lf", &volgain);
11864
11865 #ifdef ODBC_STORAGE
11866 strcpy(odbc_database, "asterisk");
11867 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11868 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11869 }
11870 strcpy(odbc_table, "voicemessages");
11871 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11872 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11873 }
11874 #endif
11875
11876 strcpy(mailcmd, SENDMAIL);
11877 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11878 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11879
11880 maxsilence = 0;
11881 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11882 maxsilence = atoi(val);
11883 if (maxsilence > 0)
11884 maxsilence *= 1000;
11885 }
11886
11887 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11888 maxmsg = MAXMSG;
11889 } else {
11890 maxmsg = atoi(val);
11891 if (maxmsg < 0) {
11892 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11893 maxmsg = MAXMSG;
11894 } else if (maxmsg > MAXMSGLIMIT) {
11895 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11896 maxmsg = MAXMSGLIMIT;
11897 }
11898 }
11899
11900 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11901 maxdeletedmsg = 0;
11902 } else {
11903 if (sscanf(val, "%30d", &x) == 1)
11904 maxdeletedmsg = x;
11905 else if (ast_true(val))
11906 maxdeletedmsg = MAXMSG;
11907 else
11908 maxdeletedmsg = 0;
11909
11910 if (maxdeletedmsg < 0) {
11911 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11912 maxdeletedmsg = MAXMSG;
11913 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11914 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11915 maxdeletedmsg = MAXMSGLIMIT;
11916 }
11917 }
11918
11919
11920 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11921 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11922 }
11923
11924
11925 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11926 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11927 }
11928
11929
11930 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11931 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11932 pwdchange = PWDCHANGE_EXTERNAL;
11933 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11934 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11935 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11936 }
11937
11938
11939 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11940 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11941 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11942 }
11943
11944 #ifdef IMAP_STORAGE
11945
11946 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11947 ast_copy_string(imapserver, val, sizeof(imapserver));
11948 } else {
11949 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11950 }
11951
11952 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11953 ast_copy_string(imapport, val, sizeof(imapport));
11954 } else {
11955 ast_copy_string(imapport, "143", sizeof(imapport));
11956 }
11957
11958 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11959 ast_copy_string(imapflags, val, sizeof(imapflags));
11960 }
11961
11962 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11963 ast_copy_string(authuser, val, sizeof(authuser));
11964 }
11965
11966 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11967 ast_copy_string(authpassword, val, sizeof(authpassword));
11968 }
11969
11970 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11971 if (ast_false(val))
11972 expungeonhangup = 0;
11973 else
11974 expungeonhangup = 1;
11975 } else {
11976 expungeonhangup = 1;
11977 }
11978
11979 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
11980 ast_copy_string(imapfolder, val, sizeof(imapfolder));
11981 } else {
11982 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
11983 }
11984 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
11985 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
11986 }
11987 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
11988 imapgreetings = ast_true(val);
11989 } else {
11990 imapgreetings = 0;
11991 }
11992 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
11993 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11994 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
11995
11996 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11997 } else {
11998 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
11999 }
12000
12001
12002
12003
12004
12005 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12006 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12007 } else {
12008 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12009 }
12010
12011 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12012 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12013 } else {
12014 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12015 }
12016
12017 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12018 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12019 } else {
12020 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12021 }
12022
12023 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12024 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12025 } else {
12026 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12027 }
12028
12029
12030 imapversion++;
12031 #endif
12032
12033 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12034 ast_copy_string(externnotify, val, sizeof(externnotify));
12035 ast_debug(1, "found externnotify: %s\n", externnotify);
12036 } else {
12037 externnotify[0] = '\0';
12038 }
12039
12040
12041 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12042 ast_debug(1, "Enabled SMDI voicemail notification\n");
12043 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12044 smdi_iface = ast_smdi_interface_find(val);
12045 } else {
12046 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12047 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12048 }
12049 if (!smdi_iface) {
12050 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12051 }
12052 }
12053
12054
12055 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12056 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12057 silencethreshold = atoi(val);
12058
12059 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12060 val = ASTERISK_USERNAME;
12061 ast_copy_string(serveremail, val, sizeof(serveremail));
12062
12063 vmmaxsecs = 0;
12064 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12065 if (sscanf(val, "%30d", &x) == 1) {
12066 vmmaxsecs = x;
12067 } else {
12068 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12069 }
12070 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12071 static int maxmessage_deprecate = 0;
12072 if (maxmessage_deprecate == 0) {
12073 maxmessage_deprecate = 1;
12074 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12075 }
12076 if (sscanf(val, "%30d", &x) == 1) {
12077 vmmaxsecs = x;
12078 } else {
12079 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12080 }
12081 }
12082
12083 vmminsecs = 0;
12084 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12085 if (sscanf(val, "%30d", &x) == 1) {
12086 vmminsecs = x;
12087 if (maxsilence / 1000 >= vmminsecs) {
12088 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12089 }
12090 } else {
12091 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12092 }
12093 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12094 static int maxmessage_deprecate = 0;
12095 if (maxmessage_deprecate == 0) {
12096 maxmessage_deprecate = 1;
12097 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12098 }
12099 if (sscanf(val, "%30d", &x) == 1) {
12100 vmminsecs = x;
12101 if (maxsilence / 1000 >= vmminsecs) {
12102 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12103 }
12104 } else {
12105 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12106 }
12107 }
12108
12109 val = ast_variable_retrieve(cfg, "general", "format");
12110 if (!val) {
12111 val = "wav";
12112 } else {
12113 tmp = ast_strdupa(val);
12114 val = ast_format_str_reduce(tmp);
12115 if (!val) {
12116 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12117 val = "wav";
12118 }
12119 }
12120 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12121
12122 skipms = 3000;
12123 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12124 if (sscanf(val, "%30d", &x) == 1) {
12125 maxgreet = x;
12126 } else {
12127 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12128 }
12129 }
12130
12131 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12132 if (sscanf(val, "%30d", &x) == 1) {
12133 skipms = x;
12134 } else {
12135 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12136 }
12137 }
12138
12139 maxlogins = 3;
12140 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12141 if (sscanf(val, "%30d", &x) == 1) {
12142 maxlogins = x;
12143 } else {
12144 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12145 }
12146 }
12147
12148 minpassword = MINPASSWORD;
12149 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12150 if (sscanf(val, "%30d", &x) == 1) {
12151 minpassword = x;
12152 } else {
12153 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12154 }
12155 }
12156
12157
12158 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12159 val = "no";
12160 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12161
12162
12163 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12164 val = "no";
12165 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12166
12167 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12168 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12169 stringp = ast_strdupa(val);
12170 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12171 if (!ast_strlen_zero(stringp)) {
12172 q = strsep(&stringp, ",");
12173 while ((*q == ' ')||(*q == '\t'))
12174 q++;
12175 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12176 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12177 } else {
12178 cidinternalcontexts[x][0] = '\0';
12179 }
12180 }
12181 }
12182 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12183 ast_debug(1, "VM Review Option disabled globally\n");
12184 val = "no";
12185 }
12186 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12187
12188
12189 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12190 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12191 val = "no";
12192 } else {
12193 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12194 }
12195 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12196 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12197 ast_debug(1, "VM next message wrap disabled globally\n");
12198 val = "no";
12199 }
12200 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12201
12202 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12203 ast_debug(1, "VM Operator break disabled globally\n");
12204 val = "no";
12205 }
12206 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12207
12208 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12209 ast_debug(1, "VM CID Info before msg disabled globally\n");
12210 val = "no";
12211 }
12212 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12213
12214 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12215 ast_debug(1, "Send Voicemail msg disabled globally\n");
12216 val = "no";
12217 }
12218 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12219
12220 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12221 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12222 val = "yes";
12223 }
12224 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12225
12226 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12227 ast_debug(1, "Move Heard enabled globally\n");
12228 val = "yes";
12229 }
12230 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12231
12232 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12233 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12234 val = "no";
12235 }
12236 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12237
12238 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12239 ast_debug(1, "Duration info before msg enabled globally\n");
12240 val = "yes";
12241 }
12242 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12243
12244 saydurationminfo = 2;
12245 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12246 if (sscanf(val, "%30d", &x) == 1) {
12247 saydurationminfo = x;
12248 } else {
12249 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12250 }
12251 }
12252
12253 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12254 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12255 val = "no";
12256 }
12257 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12258
12259 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12260 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12261 ast_debug(1, "found dialout context: %s\n", dialcontext);
12262 } else {
12263 dialcontext[0] = '\0';
12264 }
12265
12266 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12267 ast_copy_string(callcontext, val, sizeof(callcontext));
12268 ast_debug(1, "found callback context: %s\n", callcontext);
12269 } else {
12270 callcontext[0] = '\0';
12271 }
12272
12273 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12274 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12275 ast_debug(1, "found operator context: %s\n", exitcontext);
12276 } else {
12277 exitcontext[0] = '\0';
12278 }
12279
12280
12281 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12282 ast_copy_string(vm_password, val, sizeof(vm_password));
12283 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12284 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12285 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12286 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12287 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12288 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12289 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12290 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12291 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12292 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12293 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12294 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12295 }
12296 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12297 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12298 }
12299
12300 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12301 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12302 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12303 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12304 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12305 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12306 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12307 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12308 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12309 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12310
12311 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12312 val = "no";
12313 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12314
12315 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12316 val = "voicemail.conf";
12317 }
12318 if (!(strcmp(val, "spooldir"))) {
12319 passwordlocation = OPT_PWLOC_SPOOLDIR;
12320 } else {
12321 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12322 }
12323
12324 poll_freq = DEFAULT_POLL_FREQ;
12325 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12326 if (sscanf(val, "%30u", &poll_freq) != 1) {
12327 poll_freq = DEFAULT_POLL_FREQ;
12328 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12329 }
12330 }
12331
12332 poll_mailboxes = 0;
12333 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12334 poll_mailboxes = ast_true(val);
12335
12336 memset(fromstring, 0, sizeof(fromstring));
12337 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12338 strcpy(charset, "ISO-8859-1");
12339 if (emailbody) {
12340 ast_free(emailbody);
12341 emailbody = NULL;
12342 }
12343 if (emailsubject) {
12344 ast_free(emailsubject);
12345 emailsubject = NULL;
12346 }
12347 if (pagerbody) {
12348 ast_free(pagerbody);
12349 pagerbody = NULL;
12350 }
12351 if (pagersubject) {
12352 ast_free(pagersubject);
12353 pagersubject = NULL;
12354 }
12355 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12356 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12357 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12358 ast_copy_string(fromstring, val, sizeof(fromstring));
12359 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12360 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12361 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12362 ast_copy_string(charset, val, sizeof(charset));
12363 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12364 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12365 for (x = 0; x < 4; x++) {
12366 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12367 }
12368 }
12369 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12370 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12371 for (x = 0; x < 4; x++) {
12372 memcpy(&adsisec[x], &tmpadsi[x], 1);
12373 }
12374 }
12375 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12376 if (atoi(val)) {
12377 adsiver = atoi(val);
12378 }
12379 }
12380 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12381 ast_copy_string(zonetag, val, sizeof(zonetag));
12382 }
12383 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12384 ast_copy_string(locale, val, sizeof(locale));
12385 }
12386 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12387 emailsubject = ast_strdup(substitute_escapes(val));
12388 }
12389 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12390 emailbody = ast_strdup(substitute_escapes(val));
12391 }
12392 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12393 pagersubject = ast_strdup(substitute_escapes(val));
12394 }
12395 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12396 pagerbody = ast_strdup(substitute_escapes(val));
12397 }
12398
12399
12400 if (ucfg) {
12401 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12402 if (!strcasecmp(cat, "general")) {
12403 continue;
12404 }
12405 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12406 continue;
12407 if ((current = find_or_create(userscontext, cat))) {
12408 populate_defaults(current);
12409 apply_options_full(current, ast_variable_browse(ucfg, cat));
12410 ast_copy_string(current->context, userscontext, sizeof(current->context));
12411 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12412 current->passwordlocation = OPT_PWLOC_USERSCONF;
12413 }
12414
12415 switch (current->passwordlocation) {
12416 case OPT_PWLOC_SPOOLDIR:
12417 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12418 read_password_from_file(secretfn, current->password, sizeof(current->password));
12419 }
12420 }
12421 }
12422 }
12423
12424
12425 cat = ast_category_browse(cfg, NULL);
12426 while (cat) {
12427 if (strcasecmp(cat, "general")) {
12428 var = ast_variable_browse(cfg, cat);
12429 if (strcasecmp(cat, "zonemessages")) {
12430
12431 while (var) {
12432 append_mailbox(cat, var->name, var->value);
12433 var = var->next;
12434 }
12435 } else {
12436
12437 while (var) {
12438 struct vm_zone *z;
12439 if ((z = ast_malloc(sizeof(*z)))) {
12440 char *msg_format, *tzone;
12441 msg_format = ast_strdupa(var->value);
12442 tzone = strsep(&msg_format, "|,");
12443 if (msg_format) {
12444 ast_copy_string(z->name, var->name, sizeof(z->name));
12445 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12446 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12447 AST_LIST_LOCK(&zones);
12448 AST_LIST_INSERT_HEAD(&zones, z, list);
12449 AST_LIST_UNLOCK(&zones);
12450 } else {
12451 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12452 ast_free(z);
12453 }
12454 } else {
12455 AST_LIST_UNLOCK(&users);
12456 return -1;
12457 }
12458 var = var->next;
12459 }
12460 }
12461 }
12462 cat = ast_category_browse(cfg, cat);
12463 }
12464
12465 AST_LIST_UNLOCK(&users);
12466
12467 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12468 start_poll_thread();
12469 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12470 stop_poll_thread();;
12471
12472 return 0;
12473 } else {
12474 AST_LIST_UNLOCK(&users);
12475 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12476 return 0;
12477 }
12478 }
12479
12480 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12481 {
12482 int res = -1;
12483 char dir[PATH_MAX];
12484 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12485 ast_debug(2, "About to try retrieving name file %s\n", dir);
12486 RETRIEVE(dir, -1, mailbox, context);
12487 if (ast_fileexists(dir, NULL, NULL)) {
12488 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12489 }
12490 DISPOSE(dir, -1);
12491 return res;
12492 }
12493
12494 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12495 struct ast_config *pwconf;
12496 struct ast_flags config_flags = { 0 };
12497
12498 pwconf = ast_config_load(secretfn, config_flags);
12499 if (valid_config(pwconf)) {
12500 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12501 if (val) {
12502 ast_copy_string(password, val, passwordlen);
12503 ast_config_destroy(pwconf);
12504 return;
12505 }
12506 ast_config_destroy(pwconf);
12507 }
12508 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12509 }
12510
12511 static int write_password_to_file(const char *secretfn, const char *password) {
12512 struct ast_config *conf;
12513 struct ast_category *cat;
12514 struct ast_variable *var;
12515 int res = -1;
12516
12517 if (!(conf = ast_config_new())) {
12518 ast_log(LOG_ERROR, "Error creating new config structure\n");
12519 return res;
12520 }
12521 if (!(cat = ast_category_new("general", "", 1))) {
12522 ast_log(LOG_ERROR, "Error creating new category structure\n");
12523 ast_config_destroy(conf);
12524 return res;
12525 }
12526 if (!(var = ast_variable_new("password", password, ""))) {
12527 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12528 ast_config_destroy(conf);
12529 ast_category_destroy(cat);
12530 return res;
12531 }
12532 ast_category_append(conf, cat);
12533 ast_variable_append(cat, var);
12534 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12535 res = 0;
12536 } else {
12537 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12538 }
12539
12540 ast_config_destroy(conf);
12541 return res;
12542 }
12543
12544 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12545 {
12546 char *context;
12547 char *args_copy;
12548 int res;
12549
12550 if (ast_strlen_zero(data)) {
12551 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12552 return -1;
12553 }
12554
12555 args_copy = ast_strdupa(data);
12556 if ((context = strchr(args_copy, '@'))) {
12557 *context++ = '\0';
12558 } else {
12559 context = "default";
12560 }
12561
12562 if ((res = sayname(chan, args_copy, context) < 0)) {
12563 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12564 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12565 if (!res) {
12566 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12567 }
12568 }
12569
12570 return res;
12571 }
12572
12573 #ifdef TEST_FRAMEWORK
12574 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12575 {
12576 return 0;
12577 }
12578
12579 static struct ast_frame *fake_read(struct ast_channel *ast)
12580 {
12581 return &ast_null_frame;
12582 }
12583
12584 AST_TEST_DEFINE(test_voicemail_vmsayname)
12585 {
12586 char dir[PATH_MAX];
12587 char dir2[PATH_MAX];
12588 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12589 static const char TEST_EXTENSION[] = "1234";
12590
12591 struct ast_channel *test_channel1 = NULL;
12592 int res = -1;
12593
12594 static const struct ast_channel_tech fake_tech = {
12595 .write = fake_write,
12596 .read = fake_read,
12597 };
12598
12599 switch (cmd) {
12600 case TEST_INIT:
12601 info->name = "vmsayname_exec";
12602 info->category = "/apps/app_voicemail/";
12603 info->summary = "Vmsayname unit test";
12604 info->description =
12605 "This tests passing various parameters to vmsayname";
12606 return AST_TEST_NOT_RUN;
12607 case TEST_EXECUTE:
12608 break;
12609 }
12610
12611 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12612 NULL, NULL, 0, 0, "TestChannel1"))) {
12613 goto exit_vmsayname_test;
12614 }
12615
12616
12617 test_channel1->nativeformats = AST_FORMAT_GSM;
12618 test_channel1->writeformat = AST_FORMAT_GSM;
12619 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12620 test_channel1->readformat = AST_FORMAT_GSM;
12621 test_channel1->rawreadformat = AST_FORMAT_GSM;
12622 test_channel1->tech = &fake_tech;
12623
12624 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12625 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12626 if (!(res = vmsayname_exec(test_channel1, dir))) {
12627 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12628 if (ast_fileexists(dir, NULL, NULL)) {
12629 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12630 res = -1;
12631 goto exit_vmsayname_test;
12632 } else {
12633
12634 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12635 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12636 goto exit_vmsayname_test;
12637 }
12638 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12639 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12640
12641 if ((res = symlink(dir, dir2))) {
12642 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12643 goto exit_vmsayname_test;
12644 }
12645 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12646 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12647 res = vmsayname_exec(test_channel1, dir);
12648
12649
12650 unlink(dir2);
12651 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12652 rmdir(dir2);
12653 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12654 rmdir(dir2);
12655 }
12656 }
12657
12658 exit_vmsayname_test:
12659
12660 if (test_channel1) {
12661 ast_hangup(test_channel1);
12662 }
12663
12664 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12665 }
12666
12667 AST_TEST_DEFINE(test_voicemail_msgcount)
12668 {
12669 int i, j, res = AST_TEST_PASS, syserr;
12670 struct ast_vm_user *vmu;
12671 struct ast_vm_user svm;
12672 struct vm_state vms;
12673 #ifdef IMAP_STORAGE
12674 struct ast_channel *chan = NULL;
12675 #endif
12676 struct {
12677 char dir[256];
12678 char file[256];
12679 char txtfile[256];
12680 } tmp[3];
12681 char syscmd[256];
12682 const char origweasels[] = "tt-weasels";
12683 const char testcontext[] = "test";
12684 const char testmailbox[] = "00000000";
12685 const char testspec[] = "00000000@test";
12686 FILE *txt;
12687 int new, old, urgent;
12688 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12689 const int folder2mbox[3] = { 1, 11, 0 };
12690 const int expected_results[3][12] = {
12691
12692 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12693 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12694 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12695 };
12696
12697 switch (cmd) {
12698 case TEST_INIT:
12699 info->name = "test_voicemail_msgcount";
12700 info->category = "/apps/app_voicemail/";
12701 info->summary = "Test Voicemail status checks";
12702 info->description =
12703 "Verify that message counts are correct when retrieved through the public API";
12704 return AST_TEST_NOT_RUN;
12705 case TEST_EXECUTE:
12706 break;
12707 }
12708
12709
12710 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12711 if ((syserr = ast_safe_system(syscmd))) {
12712 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12713 syserr > 0 ? strerror(syserr) : "unable to fork()");
12714 return AST_TEST_FAIL;
12715 }
12716
12717 #ifdef IMAP_STORAGE
12718 if (!(chan = ast_dummy_channel_alloc())) {
12719 ast_test_status_update(test, "Unable to create dummy channel\n");
12720 return AST_TEST_FAIL;
12721 }
12722 #endif
12723
12724 if (!(vmu = find_user(&svm, testcontext, testmailbox)) &&
12725 !(vmu = find_or_create(testcontext, testmailbox))) {
12726 ast_test_status_update(test, "Cannot create vmu structure\n");
12727 ast_unreplace_sigchld();
12728 #ifdef IMAP_STORAGE
12729 chan = ast_channel_unref(chan);
12730 #endif
12731 return AST_TEST_FAIL;
12732 }
12733
12734 populate_defaults(vmu);
12735 memset(&vms, 0, sizeof(vms));
12736
12737
12738 for (i = 0; i < 3; i++) {
12739 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12740 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12741 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12742
12743 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12744 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12745 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12746 if ((syserr = ast_safe_system(syscmd))) {
12747 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12748 syserr > 0 ? strerror(syserr) : "unable to fork()");
12749 ast_unreplace_sigchld();
12750 #ifdef IMAP_STORAGE
12751 chan = ast_channel_unref(chan);
12752 #endif
12753 return AST_TEST_FAIL;
12754 }
12755 }
12756
12757 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12758 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12759 fclose(txt);
12760 } else {
12761 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12762 res = AST_TEST_FAIL;
12763 break;
12764 }
12765 open_mailbox(&vms, vmu, folder2mbox[i]);
12766 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12767
12768
12769 for (j = 0; j < 3; j++) {
12770
12771 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12772 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12773 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12774 res = AST_TEST_FAIL;
12775 }
12776 }
12777
12778 new = old = urgent = 0;
12779 if (ast_app_inboxcount(testspec, &new, &old)) {
12780 ast_test_status_update(test, "inboxcount returned failure\n");
12781 res = AST_TEST_FAIL;
12782 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12783 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12784 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12785 res = AST_TEST_FAIL;
12786 }
12787
12788 new = old = urgent = 0;
12789 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12790 ast_test_status_update(test, "inboxcount2 returned failure\n");
12791 res = AST_TEST_FAIL;
12792 } else if (old != expected_results[i][6 + 0] ||
12793 urgent != expected_results[i][6 + 1] ||
12794 new != expected_results[i][6 + 2] ) {
12795 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12796 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12797 res = AST_TEST_FAIL;
12798 }
12799
12800 new = old = urgent = 0;
12801 for (j = 0; j < 3; j++) {
12802 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12803 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12804 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12805 res = AST_TEST_FAIL;
12806 }
12807 }
12808 }
12809
12810 for (i = 0; i < 3; i++) {
12811
12812
12813
12814 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12815 DISPOSE(tmp[i].dir, 0);
12816 }
12817
12818 if (vms.deleted) {
12819 ast_free(vms.deleted);
12820 }
12821 if (vms.heard) {
12822 ast_free(vms.heard);
12823 }
12824
12825 #ifdef IMAP_STORAGE
12826 chan = ast_channel_unref(chan);
12827 #endif
12828
12829
12830 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12831 if ((syserr = ast_safe_system(syscmd))) {
12832 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12833 syserr > 0 ? strerror(syserr) : "unable to fork()");
12834 }
12835
12836 return res;
12837 }
12838
12839 AST_TEST_DEFINE(test_voicemail_notify_endl)
12840 {
12841 int res = AST_TEST_PASS;
12842 char testcontext[] = "test";
12843 char testmailbox[] = "00000000";
12844 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12845 char attach[256], attach2[256];
12846 char buf[256] = "";
12847 struct ast_channel *chan = NULL;
12848 struct ast_vm_user *vmu, vmus = {
12849 .flags = 0,
12850 };
12851 FILE *file;
12852 struct {
12853 char *name;
12854 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12855 void *location;
12856 union {
12857 int intval;
12858 char *strval;
12859 } u;
12860 } test_items[] = {
12861 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12862 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12863 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12864 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12865 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12866 { "attach2", STRPTR, attach2, .u.strval = "" },
12867 { "attach", STRPTR, attach, .u.strval = "" },
12868 };
12869 int which;
12870
12871 switch (cmd) {
12872 case TEST_INIT:
12873 info->name = "test_voicemail_notify_endl";
12874 info->category = "/apps/app_voicemail/";
12875 info->summary = "Test Voicemail notification end-of-line";
12876 info->description =
12877 "Verify that notification emails use a consistent end-of-line character";
12878 return AST_TEST_NOT_RUN;
12879 case TEST_EXECUTE:
12880 break;
12881 }
12882
12883 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12884 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12885
12886 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12887 !(vmu = find_or_create(testcontext, testmailbox))) {
12888 ast_test_status_update(test, "Cannot create vmu structure\n");
12889 return AST_TEST_NOT_RUN;
12890 }
12891
12892 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12893 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12894 return AST_TEST_NOT_RUN;
12895 }
12896
12897 populate_defaults(vmu);
12898 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12899 #ifdef IMAP_STORAGE
12900
12901 #endif
12902
12903 file = tmpfile();
12904 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12905
12906 rewind(file);
12907 if (ftruncate(fileno(file), 0)) {
12908 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12909 res = AST_TEST_FAIL;
12910 break;
12911 }
12912
12913
12914 if (test_items[which].type == INT) {
12915 *((int *) test_items[which].location) = test_items[which].u.intval;
12916 } else if (test_items[which].type == FLAGVAL) {
12917 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12918 ast_clear_flag(vmu, test_items[which].u.intval);
12919 } else {
12920 ast_set_flag(vmu, test_items[which].u.intval);
12921 }
12922 } else if (test_items[which].type == STATIC) {
12923 strcpy(test_items[which].location, test_items[which].u.strval);
12924 } else if (test_items[which].type == STRPTR) {
12925 test_items[which].location = test_items[which].u.strval;
12926 }
12927
12928 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12929 rewind(file);
12930 while (fgets(buf, sizeof(buf), file)) {
12931 if (
12932 #ifdef IMAP_STORAGE
12933 buf[strlen(buf) - 2] != '\r'
12934 #else
12935 buf[strlen(buf) - 2] == '\r'
12936 #endif
12937 || buf[strlen(buf) - 1] != '\n') {
12938 res = AST_TEST_FAIL;
12939 }
12940 }
12941 }
12942 fclose(file);
12943 return res;
12944 }
12945
12946 AST_TEST_DEFINE(test_voicemail_load_config)
12947 {
12948 int res = AST_TEST_PASS;
12949 struct ast_vm_user *vmu;
12950 struct ast_config *cfg;
12951 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
12952 int fd;
12953 FILE *file;
12954 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
12955
12956 switch (cmd) {
12957 case TEST_INIT:
12958 info->name = "test_voicemail_load_config";
12959 info->category = "/apps/app_voicemail/";
12960 info->summary = "Test loading Voicemail config";
12961 info->description =
12962 "Verify that configuration is loaded consistently. "
12963 "This is to test regressions of ASTERISK-18838 where it was noticed that "
12964 "some options were loaded after the mailboxes were instantiated, causing "
12965 "those options not to be set correctly.";
12966 return AST_TEST_NOT_RUN;
12967 case TEST_EXECUTE:
12968 break;
12969 }
12970
12971
12972 if ((fd = mkstemp(config_filename)) < 0) {
12973 return AST_TEST_FAIL;
12974 }
12975 if (!(file = fdopen(fd, "w"))) {
12976 close(fd);
12977 unlink(config_filename);
12978 return AST_TEST_FAIL;
12979 }
12980 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
12981 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
12982 fputs("00000002 => 9999,Mrs. Test\n", file);
12983 fclose(file);
12984
12985 if (!(cfg = ast_config_load(config_filename, config_flags)) || !valid_config(cfg)) {
12986 res = AST_TEST_FAIL;
12987 goto cleanup;
12988 }
12989
12990 load_config_from_memory(1, cfg, NULL);
12991 ast_config_destroy(cfg);
12992
12993 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
12994 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
12995 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
12996
12997 AST_LIST_LOCK(&users);
12998 AST_LIST_TRAVERSE(&users, vmu, list) {
12999 if (!strcmp(vmu->mailbox, "00000001")) {
13000 if (0);
13001 CHECK(vmu, callback, "othercontext")
13002 CHECK(vmu, locale, "nl_NL.UTF-8")
13003 CHECK(vmu, zonetag, "central")
13004 } else if (!strcmp(vmu->mailbox, "00000002")) {
13005 if (0);
13006 CHECK(vmu, callback, "somecontext")
13007 CHECK(vmu, locale, "de_DE.UTF-8")
13008 CHECK(vmu, zonetag, "european")
13009 }
13010 }
13011 AST_LIST_UNLOCK(&users);
13012
13013 #undef CHECK
13014
13015
13016 load_config(1);
13017
13018 cleanup:
13019 unlink(config_filename);
13020 return res;
13021 }
13022
13023 #endif
13024
13025 static int reload(void)
13026 {
13027 return load_config(1);
13028 }
13029
13030 static int unload_module(void)
13031 {
13032 int res;
13033
13034 res = ast_unregister_application(app);
13035 res |= ast_unregister_application(app2);
13036 res |= ast_unregister_application(app3);
13037 res |= ast_unregister_application(app4);
13038 res |= ast_unregister_application(sayname_app);
13039 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13040 res |= ast_manager_unregister("VoicemailUsersList");
13041 res |= ast_data_unregister(NULL);
13042 #ifdef TEST_FRAMEWORK
13043 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13044 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13045 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13046 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13047 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13048 #endif
13049 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13050 ast_uninstall_vm_functions();
13051 ao2_ref(inprocess_container, -1);
13052
13053 if (poll_thread != AST_PTHREADT_NULL)
13054 stop_poll_thread();
13055
13056 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13057 ast_unload_realtime("voicemail");
13058 ast_unload_realtime("voicemail_data");
13059
13060 free_vm_users();
13061 free_vm_zones();
13062 return res;
13063 }
13064
13065 static int load_module(void)
13066 {
13067 int res;
13068 my_umask = umask(0);
13069 umask(my_umask);
13070
13071 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13072 return AST_MODULE_LOAD_DECLINE;
13073 }
13074
13075
13076 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13077
13078 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13079 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13080 }
13081
13082 if ((res = load_config(0)))
13083 return res;
13084
13085 res = ast_register_application_xml(app, vm_exec);
13086 res |= ast_register_application_xml(app2, vm_execmain);
13087 res |= ast_register_application_xml(app3, vm_box_exists);
13088 res |= ast_register_application_xml(app4, vmauthenticate);
13089 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13090 res |= ast_custom_function_register(&mailbox_exists_acf);
13091 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13092 #ifdef TEST_FRAMEWORK
13093 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13094 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13095 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13096 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13097 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13098 #endif
13099
13100 if (res)
13101 return res;
13102
13103 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13104 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13105
13106 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13107 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13108 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13109
13110 return res;
13111 }
13112
13113 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13114 {
13115 int cmd = 0;
13116 char destination[80] = "";
13117 int retries = 0;
13118
13119 if (!num) {
13120 ast_verb(3, "Destination number will be entered manually\n");
13121 while (retries < 3 && cmd != 't') {
13122 destination[1] = '\0';
13123 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13124 if (!cmd)
13125 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13126 if (!cmd)
13127 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13128 if (!cmd) {
13129 cmd = ast_waitfordigit(chan, 6000);
13130 if (cmd)
13131 destination[0] = cmd;
13132 }
13133 if (!cmd) {
13134 retries++;
13135 } else {
13136
13137 if (cmd < 0)
13138 return 0;
13139 if (cmd == '*') {
13140 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13141 return 0;
13142 }
13143 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13144 retries++;
13145 else
13146 cmd = 't';
13147 }
13148 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13149 }
13150 if (retries >= 3) {
13151 return 0;
13152 }
13153
13154 } else {
13155 if (option_verbose > 2)
13156 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13157 ast_copy_string(destination, num, sizeof(destination));
13158 }
13159
13160 if (!ast_strlen_zero(destination)) {
13161 if (destination[strlen(destination) -1 ] == '*')
13162 return 0;
13163 if (option_verbose > 2)
13164 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13165 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13166 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13167 chan->priority = 0;
13168 return 9;
13169 }
13170 return 0;
13171 }
13172
13173
13174
13175
13176
13177
13178
13179
13180
13181
13182
13183
13184
13185
13186 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)
13187 {
13188 int res = 0;
13189 char filename[PATH_MAX];
13190 struct ast_config *msg_cfg = NULL;
13191 const char *origtime, *context;
13192 char *name, *num;
13193 int retries = 0;
13194 char *cid;
13195 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13196
13197 vms->starting = 0;
13198
13199 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13200
13201
13202 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13203 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13204 msg_cfg = ast_config_load(filename, config_flags);
13205 DISPOSE(vms->curdir, vms->curmsg);
13206 if (!valid_config(msg_cfg)) {
13207 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13208 return 0;
13209 }
13210
13211 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13212 ast_config_destroy(msg_cfg);
13213 return 0;
13214 }
13215
13216 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13217
13218 context = ast_variable_retrieve(msg_cfg, "message", "context");
13219 if (!strncasecmp("macro", context, 5))
13220 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13221 switch (option) {
13222 case 3:
13223 if (!res)
13224 res = play_message_datetime(chan, vmu, origtime, filename);
13225 if (!res)
13226 res = play_message_callerid(chan, vms, cid, context, 0);
13227
13228 res = 't';
13229 break;
13230
13231 case 2:
13232
13233 if (ast_strlen_zero(cid))
13234 break;
13235
13236 ast_callerid_parse(cid, &name, &num);
13237 while ((res > -1) && (res != 't')) {
13238 switch (res) {
13239 case '1':
13240 if (num) {
13241
13242 res = dialout(chan, vmu, num, vmu->callback);
13243 if (res) {
13244 ast_config_destroy(msg_cfg);
13245 return 9;
13246 }
13247 } else {
13248 res = '2';
13249 }
13250 break;
13251
13252 case '2':
13253
13254 if (!ast_strlen_zero(vmu->dialout)) {
13255 res = dialout(chan, vmu, NULL, vmu->dialout);
13256 if (res) {
13257 ast_config_destroy(msg_cfg);
13258 return 9;
13259 }
13260 } else {
13261 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13262 res = ast_play_and_wait(chan, "vm-sorry");
13263 }
13264 ast_config_destroy(msg_cfg);
13265 return res;
13266 case '*':
13267 res = 't';
13268 break;
13269 case '3':
13270 case '4':
13271 case '5':
13272 case '6':
13273 case '7':
13274 case '8':
13275 case '9':
13276 case '0':
13277
13278 res = ast_play_and_wait(chan, "vm-sorry");
13279 retries++;
13280 break;
13281 default:
13282 if (num) {
13283 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13284 res = ast_play_and_wait(chan, "vm-num-i-have");
13285 if (!res)
13286 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13287 if (!res)
13288 res = ast_play_and_wait(chan, "vm-tocallnum");
13289
13290 if (!ast_strlen_zero(vmu->dialout)) {
13291 if (!res)
13292 res = ast_play_and_wait(chan, "vm-calldiffnum");
13293 }
13294 } else {
13295 res = ast_play_and_wait(chan, "vm-nonumber");
13296 if (!ast_strlen_zero(vmu->dialout)) {
13297 if (!res)
13298 res = ast_play_and_wait(chan, "vm-toenternumber");
13299 }
13300 }
13301 if (!res) {
13302 res = ast_play_and_wait(chan, "vm-star-cancel");
13303 }
13304 if (!res) {
13305 res = ast_waitfordigit(chan, 6000);
13306 }
13307 if (!res) {
13308 retries++;
13309 if (retries > 3) {
13310 res = 't';
13311 }
13312 }
13313 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13314 break;
13315
13316 }
13317 if (res == 't')
13318 res = 0;
13319 else if (res == '*')
13320 res = -1;
13321 }
13322 break;
13323
13324 case 1:
13325
13326 if (ast_strlen_zero(cid))
13327 break;
13328
13329 ast_callerid_parse(cid, &name, &num);
13330 if (!num) {
13331 ast_verb(3, "No CID number available, no reply sent\n");
13332 if (!res)
13333 res = ast_play_and_wait(chan, "vm-nonumber");
13334 ast_config_destroy(msg_cfg);
13335 return res;
13336 } else {
13337 struct ast_vm_user vmu2;
13338 if (find_user(&vmu2, vmu->context, num)) {
13339 struct leave_vm_options leave_options;
13340 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13341 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13342
13343 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13344
13345 memset(&leave_options, 0, sizeof(leave_options));
13346 leave_options.record_gain = record_gain;
13347 res = leave_voicemail(chan, mailbox, &leave_options);
13348 if (!res)
13349 res = 't';
13350 ast_config_destroy(msg_cfg);
13351 return res;
13352 } else {
13353
13354 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13355 ast_play_and_wait(chan, "vm-nobox");
13356 res = 't';
13357 ast_config_destroy(msg_cfg);
13358 return res;
13359 }
13360 }
13361 res = 0;
13362
13363 break;
13364 }
13365
13366 ast_config_destroy(msg_cfg);
13367
13368 #ifndef IMAP_STORAGE
13369 if (!res) {
13370 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13371 vms->heard[msg] = 1;
13372 res = wait_file(chan, vms, vms->fn);
13373 }
13374 #endif
13375 return res;
13376 }
13377
13378 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13379 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13380 signed char record_gain, struct vm_state *vms, char *flag)
13381 {
13382
13383 int res = 0;
13384 int cmd = 0;
13385 int max_attempts = 3;
13386 int attempts = 0;
13387 int recorded = 0;
13388 int msg_exists = 0;
13389 signed char zero_gain = 0;
13390 char tempfile[PATH_MAX];
13391 char *acceptdtmf = "#";
13392 char *canceldtmf = "";
13393 int canceleddtmf = 0;
13394
13395
13396
13397
13398 if (duration == NULL) {
13399 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13400 return -1;
13401 }
13402
13403 if (!outsidecaller)
13404 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13405 else
13406 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13407
13408 cmd = '3';
13409
13410 while ((cmd >= 0) && (cmd != 't')) {
13411 switch (cmd) {
13412 case '1':
13413 if (!msg_exists) {
13414
13415 cmd = '3';
13416 break;
13417 } else {
13418
13419 ast_verb(3, "Saving message as is\n");
13420 if (!outsidecaller)
13421 ast_filerename(tempfile, recordfile, NULL);
13422 ast_stream_and_wait(chan, "vm-msgsaved", "");
13423 if (!outsidecaller) {
13424
13425 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13426 DISPOSE(recordfile, -1);
13427 }
13428 cmd = 't';
13429 return res;
13430 }
13431 case '2':
13432
13433 ast_verb(3, "Reviewing the message\n");
13434 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13435 break;
13436 case '3':
13437 msg_exists = 0;
13438
13439 if (recorded == 1)
13440 ast_verb(3, "Re-recording the message\n");
13441 else
13442 ast_verb(3, "Recording the message\n");
13443
13444 if (recorded && outsidecaller) {
13445 cmd = ast_play_and_wait(chan, INTRO);
13446 cmd = ast_play_and_wait(chan, "beep");
13447 }
13448 recorded = 1;
13449
13450 if (record_gain)
13451 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13452 if (ast_test_flag(vmu, VM_OPERATOR))
13453 canceldtmf = "0";
13454 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13455 if (strchr(canceldtmf, cmd)) {
13456
13457 canceleddtmf = 1;
13458 }
13459 if (record_gain)
13460 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13461 if (cmd == -1) {
13462
13463 if (!outsidecaller) {
13464
13465 ast_filedelete(tempfile, NULL);
13466 }
13467 return cmd;
13468 }
13469 if (cmd == '0') {
13470 break;
13471 } else if (cmd == '*') {
13472 break;
13473 #if 0
13474 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13475
13476 ast_verb(3, "Message too short\n");
13477 cmd = ast_play_and_wait(chan, "vm-tooshort");
13478 cmd = ast_filedelete(tempfile, NULL);
13479 break;
13480 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13481
13482 ast_verb(3, "Nothing recorded\n");
13483 cmd = ast_filedelete(tempfile, NULL);
13484 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13485 if (!cmd)
13486 cmd = ast_play_and_wait(chan, "vm-speakup");
13487 break;
13488 #endif
13489 } else {
13490
13491 msg_exists = 1;
13492 cmd = 0;
13493 }
13494 break;
13495 case '4':
13496 if (outsidecaller) {
13497
13498 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13499 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13500 res = ast_play_and_wait(chan, "vm-marked-urgent");
13501 strcpy(flag, "Urgent");
13502 } else if (flag) {
13503 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13504 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
13505 strcpy(flag, "");
13506 } else {
13507 ast_play_and_wait(chan, "vm-sorry");
13508 }
13509 cmd = 0;
13510 } else {
13511 cmd = ast_play_and_wait(chan, "vm-sorry");
13512 }
13513 break;
13514 case '5':
13515 case '6':
13516 case '7':
13517 case '8':
13518 case '9':
13519 case '*':
13520 case '#':
13521 cmd = ast_play_and_wait(chan, "vm-sorry");
13522 break;
13523 #if 0
13524
13525
13526 case '*':
13527
13528 cmd = ast_play_and_wait(chan, "vm-deleted");
13529 cmd = ast_filedelete(tempfile, NULL);
13530 if (outsidecaller) {
13531 res = vm_exec(chan, NULL);
13532 return res;
13533 }
13534 else
13535 return 1;
13536 #endif
13537 case '0':
13538 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13539 cmd = ast_play_and_wait(chan, "vm-sorry");
13540 break;
13541 }
13542 if (msg_exists || recorded) {
13543 cmd = ast_play_and_wait(chan, "vm-saveoper");
13544 if (!cmd)
13545 cmd = ast_waitfordigit(chan, 3000);
13546 if (cmd == '1') {
13547 ast_filerename(tempfile, recordfile, NULL);
13548 ast_play_and_wait(chan, "vm-msgsaved");
13549 cmd = '0';
13550 } else if (cmd == '4') {
13551 if (flag) {
13552 ast_play_and_wait(chan, "vm-marked-urgent");
13553 strcpy(flag, "Urgent");
13554 }
13555 ast_play_and_wait(chan, "vm-msgsaved");
13556 cmd = '0';
13557 } else {
13558 ast_play_and_wait(chan, "vm-deleted");
13559 DELETE(tempfile, -1, tempfile, vmu);
13560 cmd = '0';
13561 }
13562 }
13563 return cmd;
13564 default:
13565
13566
13567
13568 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13569 return cmd;
13570 if (msg_exists) {
13571 cmd = ast_play_and_wait(chan, "vm-review");
13572 if (!cmd && outsidecaller) {
13573 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13574 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13575 } else if (flag) {
13576 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13577 }
13578 }
13579 } else {
13580 cmd = ast_play_and_wait(chan, "vm-torerecord");
13581 if (!cmd)
13582 cmd = ast_waitfordigit(chan, 600);
13583 }
13584
13585 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13586 cmd = ast_play_and_wait(chan, "vm-reachoper");
13587 if (!cmd)
13588 cmd = ast_waitfordigit(chan, 600);
13589 }
13590 #if 0
13591 if (!cmd)
13592 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13593 #endif
13594 if (!cmd)
13595 cmd = ast_waitfordigit(chan, 6000);
13596 if (!cmd) {
13597 attempts++;
13598 }
13599 if (attempts > max_attempts) {
13600 cmd = 't';
13601 }
13602 }
13603 }
13604 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13605
13606 ast_filedelete(tempfile, NULL);
13607 }
13608
13609 if (cmd != 't' && outsidecaller)
13610 ast_play_and_wait(chan, "vm-goodbye");
13611
13612 return cmd;
13613 }
13614
13615
13616
13617
13618
13619 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13620 .load = load_module,
13621 .unload = unload_module,
13622 .reload = reload,
13623 .nonoptreq = "res_adsi,res_smdi",
13624 );