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: 376262 $")
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[VMSTATE_MAX_MSG_ARRAY];
00683 MAILSTREAM *mailstream;
00684 int vmArrayIndex;
00685 char imapuser[80];
00686 char imapfolder[64];
00687 int imapversion;
00688 int interactive;
00689 char introfn[PATH_MAX];
00690 unsigned int quota_limit;
00691 unsigned int quota_usage;
00692 struct vm_state *persist_vms;
00693 #endif
00694 };
00695
00696 #ifdef ODBC_STORAGE
00697 static char odbc_database[80];
00698 static char odbc_table[80];
00699 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00700 #define DISPOSE(a,b) remove_file(a,b)
00701 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00702 #define EXISTS(a,b,c,d) (message_exists(a,b))
00703 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00704 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00705 #define DELETE(a,b,c,d) (delete_file(a,b))
00706 #else
00707 #ifdef IMAP_STORAGE
00708 #define DISPOSE(a,b) (imap_remove_file(a,b))
00709 #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))
00710 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00711 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00712 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00713 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00714 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00715 #else
00716 #define RETRIEVE(a,b,c,d)
00717 #define DISPOSE(a,b)
00718 #define STORE(a,b,c,d,e,f,g,h,i,j)
00719 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00720 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00721 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00722 #define DELETE(a,b,c,d) (vm_delete(c))
00723 #endif
00724 #endif
00725
00726 static char VM_SPOOL_DIR[PATH_MAX];
00727
00728 static char ext_pass_cmd[128];
00729 static char ext_pass_check_cmd[128];
00730
00731 static int my_umask;
00732
00733 #define PWDCHANGE_INTERNAL (1 << 1)
00734 #define PWDCHANGE_EXTERNAL (1 << 2)
00735 static int pwdchange = PWDCHANGE_INTERNAL;
00736
00737 #ifdef ODBC_STORAGE
00738 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00739 #else
00740 # ifdef IMAP_STORAGE
00741 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00742 # else
00743 # define tdesc "Comedian Mail (Voicemail System)"
00744 # endif
00745 #endif
00746
00747 static char userscontext[AST_MAX_EXTENSION] = "default";
00748
00749 static char *addesc = "Comedian Mail";
00750
00751
00752 static char *app = "VoiceMail";
00753
00754
00755 static char *app2 = "VoiceMailMain";
00756
00757 static char *app3 = "MailboxExists";
00758 static char *app4 = "VMAuthenticate";
00759
00760 static char *sayname_app = "VMSayName";
00761
00762 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00763 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00764 static char zonetag[80];
00765 static char locale[20];
00766 static int maxsilence;
00767 static int maxmsg;
00768 static int maxdeletedmsg;
00769 static int silencethreshold = 128;
00770 static char serveremail[80];
00771 static char mailcmd[160];
00772 static char externnotify[160];
00773 static struct ast_smdi_interface *smdi_iface = NULL;
00774 static char vmfmts[80];
00775 static double volgain;
00776 static int vmminsecs;
00777 static int vmmaxsecs;
00778 static int maxgreet;
00779 static int skipms;
00780 static int maxlogins;
00781 static int minpassword;
00782 static int passwordlocation;
00783
00784
00785
00786 static unsigned int poll_mailboxes;
00787
00788
00789 static unsigned int poll_freq;
00790
00791 #define DEFAULT_POLL_FREQ 30
00792
00793 AST_MUTEX_DEFINE_STATIC(poll_lock);
00794 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00795 static pthread_t poll_thread = AST_PTHREADT_NULL;
00796 static unsigned char poll_thread_run;
00797
00798
00799 static struct ast_event_sub *mwi_sub_sub;
00800
00801 static struct ast_event_sub *mwi_unsub_sub;
00802
00803
00804
00805
00806
00807
00808
00809
00810 struct mwi_sub {
00811 AST_RWLIST_ENTRY(mwi_sub) entry;
00812 int old_urgent;
00813 int old_new;
00814 int old_old;
00815 uint32_t uniqueid;
00816 char mailbox[1];
00817 };
00818
00819 struct mwi_sub_task {
00820 const char *mailbox;
00821 const char *context;
00822 uint32_t uniqueid;
00823 };
00824
00825 static struct ast_taskprocessor *mwi_subscription_tps;
00826
00827 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00828
00829
00830 static char listen_control_forward_key[12];
00831 static char listen_control_reverse_key[12];
00832 static char listen_control_pause_key[12];
00833 static char listen_control_restart_key[12];
00834 static char listen_control_stop_key[12];
00835
00836
00837 static char vm_password[80] = "vm-password";
00838 static char vm_newpassword[80] = "vm-newpassword";
00839 static char vm_passchanged[80] = "vm-passchanged";
00840 static char vm_reenterpassword[80] = "vm-reenterpassword";
00841 static char vm_mismatch[80] = "vm-mismatch";
00842 static char vm_invalid_password[80] = "vm-invalid-password";
00843 static char vm_pls_try_again[80] = "vm-pls-try-again";
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855 static char vm_prepend_timeout[80] = "vm-then-pound";
00856
00857 static struct ast_flags globalflags = {0};
00858
00859 static int saydurationminfo;
00860
00861 static char dialcontext[AST_MAX_CONTEXT] = "";
00862 static char callcontext[AST_MAX_CONTEXT] = "";
00863 static char exitcontext[AST_MAX_CONTEXT] = "";
00864
00865 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00866
00867
00868 static char *emailbody = NULL;
00869 static char *emailsubject = NULL;
00870 static char *pagerbody = NULL;
00871 static char *pagersubject = NULL;
00872 static char fromstring[100];
00873 static char pagerfromstring[100];
00874 static char charset[32] = "ISO-8859-1";
00875
00876 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00877 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00878 static int adsiver = 1;
00879 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00880 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00881
00882
00883 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00884 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);
00885 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00886 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00887 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00888 signed char record_gain, struct vm_state *vms, char *flag);
00889 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00890 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00891 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);
00892 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);
00893 static void apply_options(struct ast_vm_user *vmu, const char *options);
00894 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);
00895 static int is_valid_dtmf(const char *key);
00896 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00897 static int write_password_to_file(const char *secretfn, const char *password);
00898 static const char *substitute_escapes(const char *value);
00899 static void free_user(struct ast_vm_user *vmu);
00900
00901 struct ao2_container *inprocess_container;
00902
00903 struct inprocess {
00904 int count;
00905 char *context;
00906 char mailbox[0];
00907 };
00908
00909 static int inprocess_hash_fn(const void *obj, const int flags)
00910 {
00911 const struct inprocess *i = obj;
00912 return atoi(i->mailbox);
00913 }
00914
00915 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00916 {
00917 struct inprocess *i = obj, *j = arg;
00918 if (strcmp(i->mailbox, j->mailbox)) {
00919 return 0;
00920 }
00921 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00922 }
00923
00924 static int inprocess_count(const char *context, const char *mailbox, int delta)
00925 {
00926 struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00927 arg->context = arg->mailbox + strlen(mailbox) + 1;
00928 strcpy(arg->mailbox, mailbox);
00929 strcpy(arg->context, context);
00930 ao2_lock(inprocess_container);
00931 if ((i = ao2_find(inprocess_container, arg, 0))) {
00932 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00933 ao2_unlock(inprocess_container);
00934 ao2_ref(i, -1);
00935 return ret;
00936 }
00937 if (delta < 0) {
00938 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00939 }
00940 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00941 ao2_unlock(inprocess_container);
00942 return 0;
00943 }
00944 i->context = i->mailbox + strlen(mailbox) + 1;
00945 strcpy(i->mailbox, mailbox);
00946 strcpy(i->context, context);
00947 i->count = delta;
00948 ao2_link(inprocess_container, i);
00949 ao2_unlock(inprocess_container);
00950 ao2_ref(i, -1);
00951 return 0;
00952 }
00953
00954 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00955 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00956 #endif
00957
00958
00959
00960
00961
00962
00963
00964 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00965 {
00966 char *bufptr = buf;
00967 for (; *input; input++) {
00968 if (*input < 32) {
00969 continue;
00970 }
00971 *bufptr++ = *input;
00972 if (bufptr == buf + buflen - 1) {
00973 break;
00974 }
00975 }
00976 *bufptr = '\0';
00977 return buf;
00978 }
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994 static void populate_defaults(struct ast_vm_user *vmu)
00995 {
00996 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00997 vmu->passwordlocation = passwordlocation;
00998 if (saydurationminfo) {
00999 vmu->saydurationm = saydurationminfo;
01000 }
01001 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01002 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01003 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01004 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01005 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01006 if (vmminsecs) {
01007 vmu->minsecs = vmminsecs;
01008 }
01009 if (vmmaxsecs) {
01010 vmu->maxsecs = vmmaxsecs;
01011 }
01012 if (maxmsg) {
01013 vmu->maxmsg = maxmsg;
01014 }
01015 if (maxdeletedmsg) {
01016 vmu->maxdeletedmsg = maxdeletedmsg;
01017 }
01018 vmu->volgain = volgain;
01019 ast_free(vmu->emailsubject);
01020 vmu->emailsubject = NULL;
01021 ast_free(vmu->emailbody);
01022 vmu->emailbody = NULL;
01023 #ifdef IMAP_STORAGE
01024 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01025 #endif
01026 }
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01037 {
01038 int x;
01039 if (!strcasecmp(var, "attach")) {
01040 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01041 } else if (!strcasecmp(var, "attachfmt")) {
01042 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01043 } else if (!strcasecmp(var, "serveremail")) {
01044 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01045 } else if (!strcasecmp(var, "emailbody")) {
01046 vmu->emailbody = ast_strdup(substitute_escapes(value));
01047 } else if (!strcasecmp(var, "emailsubject")) {
01048 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01049 } else if (!strcasecmp(var, "language")) {
01050 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01051 } else if (!strcasecmp(var, "tz")) {
01052 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01053 } else if (!strcasecmp(var, "locale")) {
01054 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01055 #ifdef IMAP_STORAGE
01056 } else if (!strcasecmp(var, "imapuser")) {
01057 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01058 vmu->imapversion = imapversion;
01059 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01060 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01061 vmu->imapversion = imapversion;
01062 } else if (!strcasecmp(var, "imapfolder")) {
01063 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01064 } else if (!strcasecmp(var, "imapvmshareid")) {
01065 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01066 vmu->imapversion = imapversion;
01067 #endif
01068 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01069 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01070 } else if (!strcasecmp(var, "saycid")){
01071 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01072 } else if (!strcasecmp(var, "sendvoicemail")){
01073 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01074 } else if (!strcasecmp(var, "review")){
01075 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01076 } else if (!strcasecmp(var, "tempgreetwarn")){
01077 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01078 } else if (!strcasecmp(var, "messagewrap")){
01079 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01080 } else if (!strcasecmp(var, "operator")) {
01081 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01082 } else if (!strcasecmp(var, "envelope")){
01083 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01084 } else if (!strcasecmp(var, "moveheard")){
01085 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01086 } else if (!strcasecmp(var, "sayduration")){
01087 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01088 } else if (!strcasecmp(var, "saydurationm")){
01089 if (sscanf(value, "%30d", &x) == 1) {
01090 vmu->saydurationm = x;
01091 } else {
01092 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01093 }
01094 } else if (!strcasecmp(var, "forcename")){
01095 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01096 } else if (!strcasecmp(var, "forcegreetings")){
01097 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01098 } else if (!strcasecmp(var, "callback")) {
01099 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01100 } else if (!strcasecmp(var, "dialout")) {
01101 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01102 } else if (!strcasecmp(var, "exitcontext")) {
01103 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01104 } else if (!strcasecmp(var, "minsecs")) {
01105 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01106 vmu->minsecs = x;
01107 } else {
01108 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01109 vmu->minsecs = vmminsecs;
01110 }
01111 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01112 vmu->maxsecs = atoi(value);
01113 if (vmu->maxsecs <= 0) {
01114 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01115 vmu->maxsecs = vmmaxsecs;
01116 } else {
01117 vmu->maxsecs = atoi(value);
01118 }
01119 if (!strcasecmp(var, "maxmessage"))
01120 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01121 } else if (!strcasecmp(var, "maxmsg")) {
01122 vmu->maxmsg = atoi(value);
01123
01124 if (vmu->maxmsg < 0) {
01125 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01126 vmu->maxmsg = MAXMSG;
01127 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01128 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01129 vmu->maxmsg = MAXMSGLIMIT;
01130 }
01131 } else if (!strcasecmp(var, "nextaftercmd")) {
01132 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01133 } else if (!strcasecmp(var, "backupdeleted")) {
01134 if (sscanf(value, "%30d", &x) == 1)
01135 vmu->maxdeletedmsg = x;
01136 else if (ast_true(value))
01137 vmu->maxdeletedmsg = MAXMSG;
01138 else
01139 vmu->maxdeletedmsg = 0;
01140
01141 if (vmu->maxdeletedmsg < 0) {
01142 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01143 vmu->maxdeletedmsg = MAXMSG;
01144 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01145 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01146 vmu->maxdeletedmsg = MAXMSGLIMIT;
01147 }
01148 } else if (!strcasecmp(var, "volgain")) {
01149 sscanf(value, "%30lf", &vmu->volgain);
01150 } else if (!strcasecmp(var, "passwordlocation")) {
01151 if (!strcasecmp(value, "spooldir")) {
01152 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01153 } else {
01154 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01155 }
01156 } else if (!strcasecmp(var, "options")) {
01157 apply_options(vmu, value);
01158 }
01159 }
01160
01161 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01162 {
01163 int fds[2], pid = 0;
01164
01165 memset(buf, 0, len);
01166
01167 if (pipe(fds)) {
01168 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01169 } else {
01170
01171 pid = ast_safe_fork(0);
01172
01173 if (pid < 0) {
01174
01175 close(fds[0]);
01176 close(fds[1]);
01177 snprintf(buf, len, "FAILURE: Fork failed");
01178 } else if (pid) {
01179
01180 close(fds[1]);
01181 if (read(fds[0], buf, len) < 0) {
01182 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01183 }
01184 close(fds[0]);
01185 } else {
01186
01187 AST_DECLARE_APP_ARGS(arg,
01188 AST_APP_ARG(v)[20];
01189 );
01190 char *mycmd = ast_strdupa(command);
01191
01192 close(fds[0]);
01193 dup2(fds[1], STDOUT_FILENO);
01194 close(fds[1]);
01195 ast_close_fds_above_n(STDOUT_FILENO);
01196
01197 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01198
01199 execv(arg.v[0], arg.v);
01200 printf("FAILURE: %s", strerror(errno));
01201 _exit(0);
01202 }
01203 }
01204 return buf;
01205 }
01206
01207
01208
01209
01210
01211
01212
01213
01214 static int check_password(struct ast_vm_user *vmu, char *password)
01215 {
01216
01217 if (strlen(password) < minpassword)
01218 return 1;
01219
01220 if (!ast_strlen_zero(password) && password[0] == '*')
01221 return 1;
01222 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01223 char cmd[255], buf[255];
01224
01225 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01226
01227 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01228 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01229 ast_debug(5, "Result: %s\n", buf);
01230 if (!strncasecmp(buf, "VALID", 5)) {
01231 ast_debug(3, "Passed password check: '%s'\n", buf);
01232 return 0;
01233 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01234 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01235 return 0;
01236 } else {
01237 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01238 return 1;
01239 }
01240 }
01241 }
01242 return 0;
01243 }
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01256 {
01257 int res = -1;
01258 if (!strcmp(vmu->password, password)) {
01259
01260 return 0;
01261 }
01262
01263 if (strlen(password) > 10) {
01264 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01265 }
01266 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01267 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01268 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01269 res = 0;
01270 }
01271 return res;
01272 }
01273
01274
01275
01276
01277 static void apply_options(struct ast_vm_user *vmu, const char *options)
01278 {
01279 char *stringp;
01280 char *s;
01281 char *var, *value;
01282 stringp = ast_strdupa(options);
01283 while ((s = strsep(&stringp, "|"))) {
01284 value = s;
01285 if ((var = strsep(&value, "=")) && value) {
01286 apply_option(vmu, var, value);
01287 }
01288 }
01289 }
01290
01291
01292
01293
01294
01295
01296 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01297 {
01298 for (; var; var = var->next) {
01299 if (!strcasecmp(var->name, "vmsecret")) {
01300 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01301 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01302 if (ast_strlen_zero(retval->password)) {
01303 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01304 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01305 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01306 } else {
01307 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01308 }
01309 }
01310 } else if (!strcasecmp(var->name, "uniqueid")) {
01311 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01312 } else if (!strcasecmp(var->name, "pager")) {
01313 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01314 } else if (!strcasecmp(var->name, "email")) {
01315 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01316 } else if (!strcasecmp(var->name, "fullname")) {
01317 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01318 } else if (!strcasecmp(var->name, "context")) {
01319 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01320 } else if (!strcasecmp(var->name, "emailsubject")) {
01321 ast_free(retval->emailsubject);
01322 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01323 } else if (!strcasecmp(var->name, "emailbody")) {
01324 ast_free(retval->emailbody);
01325 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01326 #ifdef IMAP_STORAGE
01327 } else if (!strcasecmp(var->name, "imapuser")) {
01328 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01329 retval->imapversion = imapversion;
01330 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01331 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01332 retval->imapversion = imapversion;
01333 } else if (!strcasecmp(var->name, "imapfolder")) {
01334 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01335 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01336 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01337 retval->imapversion = imapversion;
01338 #endif
01339 } else
01340 apply_option(retval, var->name, var->value);
01341 }
01342 }
01343
01344
01345
01346
01347
01348
01349
01350
01351 static int is_valid_dtmf(const char *key)
01352 {
01353 int i;
01354 char *local_key = ast_strdupa(key);
01355
01356 for (i = 0; i < strlen(key); ++i) {
01357 if (!strchr(VALID_DTMF, *local_key)) {
01358 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01359 return 0;
01360 }
01361 local_key++;
01362 }
01363 return 1;
01364 }
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01377 {
01378 struct ast_variable *var;
01379 struct ast_vm_user *retval;
01380
01381 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01382 if (ivm) {
01383 memset(retval, 0, sizeof(*retval));
01384 }
01385 populate_defaults(retval);
01386 if (!ivm) {
01387 ast_set_flag(retval, VM_ALLOCED);
01388 }
01389 if (mailbox) {
01390 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01391 }
01392 if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
01393 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01394 } else {
01395 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01396 }
01397 if (var) {
01398 apply_options_full(retval, var);
01399 ast_variables_destroy(var);
01400 } else {
01401 if (!ivm)
01402 free_user(retval);
01403 retval = NULL;
01404 }
01405 }
01406 return retval;
01407 }
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01418 {
01419
01420 struct ast_vm_user *vmu = NULL, *cur;
01421 AST_LIST_LOCK(&users);
01422
01423 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01424 context = "default";
01425
01426 AST_LIST_TRAVERSE(&users, cur, list) {
01427 #ifdef IMAP_STORAGE
01428 if (cur->imapversion != imapversion) {
01429 continue;
01430 }
01431 #endif
01432 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01433 break;
01434 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01435 break;
01436 }
01437 if (cur) {
01438
01439 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01440 *vmu = *cur;
01441 if (!ivm) {
01442 vmu->emailbody = ast_strdup(cur->emailbody);
01443 vmu->emailsubject = ast_strdup(cur->emailsubject);
01444 }
01445 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01446 AST_LIST_NEXT(vmu, list) = NULL;
01447 }
01448 } else
01449 vmu = find_user_realtime(ivm, context, mailbox);
01450 AST_LIST_UNLOCK(&users);
01451 return vmu;
01452 }
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01465 {
01466
01467 struct ast_vm_user *cur;
01468 int res = -1;
01469 AST_LIST_LOCK(&users);
01470 AST_LIST_TRAVERSE(&users, cur, list) {
01471 if ((!context || !strcasecmp(context, cur->context)) &&
01472 (!strcasecmp(mailbox, cur->mailbox)))
01473 break;
01474 }
01475 if (cur) {
01476 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01477 res = 0;
01478 }
01479 AST_LIST_UNLOCK(&users);
01480 return res;
01481 }
01482
01483
01484
01485
01486
01487
01488
01489
01490 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01491 {
01492 struct ast_config *cfg = NULL;
01493 struct ast_variable *var = NULL;
01494 struct ast_category *cat = NULL;
01495 char *category = NULL, *value = NULL, *new = NULL;
01496 const char *tmp = NULL;
01497 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01498 char secretfn[PATH_MAX] = "";
01499 int found = 0;
01500
01501 if (!change_password_realtime(vmu, newpassword))
01502 return;
01503
01504
01505 switch (vmu->passwordlocation) {
01506 case OPT_PWLOC_SPOOLDIR:
01507 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01508 if (write_password_to_file(secretfn, newpassword) == 0) {
01509 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01510 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01511 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01512 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01513 break;
01514 } else {
01515 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01516 }
01517
01518 case OPT_PWLOC_VOICEMAILCONF:
01519 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01520 while ((category = ast_category_browse(cfg, category))) {
01521 if (!strcasecmp(category, vmu->context)) {
01522 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01523 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01524 break;
01525 }
01526 value = strstr(tmp, ",");
01527 if (!value) {
01528 new = ast_alloca(strlen(newpassword)+1);
01529 sprintf(new, "%s", newpassword);
01530 } else {
01531 new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
01532 sprintf(new, "%s%s", newpassword, value);
01533 }
01534 if (!(cat = ast_category_get(cfg, category))) {
01535 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01536 break;
01537 }
01538 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01539 found = 1;
01540 }
01541 }
01542
01543 if (found) {
01544 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01545 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01546 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01547 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01548 break;
01549 }
01550 }
01551
01552 case OPT_PWLOC_USERSCONF:
01553
01554
01555 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01556 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01557 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01558 ast_debug(4, "users.conf: %s\n", category);
01559 if (!strcasecmp(category, vmu->mailbox)) {
01560 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01561 ast_debug(3, "looks like we need to make vmsecret!\n");
01562 var = ast_variable_new("vmsecret", newpassword, "");
01563 } else {
01564 var = NULL;
01565 }
01566 new = ast_alloca(strlen(newpassword) + 1);
01567 sprintf(new, "%s", newpassword);
01568 if (!(cat = ast_category_get(cfg, category))) {
01569 ast_debug(4, "failed to get category!\n");
01570 ast_free(var);
01571 break;
01572 }
01573 if (!var) {
01574 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01575 } else {
01576 ast_variable_append(cat, var);
01577 }
01578 found = 1;
01579 break;
01580 }
01581 }
01582
01583 if (found) {
01584 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01585 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01586 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01587 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01588 }
01589 }
01590 }
01591 }
01592
01593 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01594 {
01595 char buf[255];
01596 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01597 ast_debug(1, "External password: %s\n",buf);
01598 if (!ast_safe_system(buf)) {
01599 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01600 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01601
01602 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01603 }
01604 }
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01620 {
01621 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01622 }
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636 static int make_file(char *dest, const int len, const char *dir, const int num)
01637 {
01638 return snprintf(dest, len, "%s/msg%04d", dir, num);
01639 }
01640
01641
01642 static FILE *vm_mkftemp(char *template)
01643 {
01644 FILE *p = NULL;
01645 int pfd = mkstemp(template);
01646 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01647 if (pfd > -1) {
01648 p = fdopen(pfd, "w+");
01649 if (!p) {
01650 close(pfd);
01651 pfd = -1;
01652 }
01653 }
01654 return p;
01655 }
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01666 {
01667 mode_t mode = VOICEMAIL_DIR_MODE;
01668 int res;
01669
01670 make_dir(dest, len, context, ext, folder);
01671 if ((res = ast_mkdir(dest, mode))) {
01672 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01673 return -1;
01674 }
01675 return 0;
01676 }
01677
01678 static const char * const mailbox_folders[] = {
01679 #ifdef IMAP_STORAGE
01680 imapfolder,
01681 #else
01682 "INBOX",
01683 #endif
01684 "Old",
01685 "Work",
01686 "Family",
01687 "Friends",
01688 "Cust1",
01689 "Cust2",
01690 "Cust3",
01691 "Cust4",
01692 "Cust5",
01693 "Deleted",
01694 "Urgent",
01695 };
01696
01697 static const char *mbox(struct ast_vm_user *vmu, int id)
01698 {
01699 #ifdef IMAP_STORAGE
01700 if (vmu && id == 0) {
01701 return vmu->imapfolder;
01702 }
01703 #endif
01704 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01705 }
01706
01707 static int get_folder_by_name(const char *name)
01708 {
01709 size_t i;
01710
01711 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01712 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01713 return i;
01714 }
01715 }
01716
01717 return -1;
01718 }
01719
01720 static void free_user(struct ast_vm_user *vmu)
01721 {
01722 if (ast_test_flag(vmu, VM_ALLOCED)) {
01723
01724 ast_free(vmu->emailbody);
01725 vmu->emailbody = NULL;
01726
01727 ast_free(vmu->emailsubject);
01728 vmu->emailsubject = NULL;
01729
01730 ast_free(vmu);
01731 }
01732 }
01733
01734 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01735
01736 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01737
01738
01739 if (vms->deleted) {
01740 ast_free(vms->deleted);
01741 vms->deleted = NULL;
01742 }
01743 if (vms->heard) {
01744 ast_free(vms->heard);
01745 vms->heard = NULL;
01746 }
01747 vms->dh_arraysize = 0;
01748
01749 if (arraysize > 0) {
01750 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01751 return -1;
01752 }
01753 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01754 ast_free(vms->deleted);
01755 vms->deleted = NULL;
01756 return -1;
01757 }
01758 vms->dh_arraysize = arraysize;
01759 }
01760
01761 return 0;
01762 }
01763
01764
01765
01766 #ifdef IMAP_STORAGE
01767 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01768 {
01769 char arg[10];
01770 struct vm_state *vms;
01771 unsigned long messageNum;
01772
01773
01774 if (msgnum < 0 && !imapgreetings) {
01775 ast_filedelete(file, NULL);
01776 return;
01777 }
01778
01779 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01780 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);
01781 return;
01782 }
01783
01784 if (msgnum < 0) {
01785 imap_delete_old_greeting(file, vms);
01786 return;
01787 }
01788
01789
01790
01791 messageNum = vms->msgArray[msgnum];
01792 if (messageNum == 0) {
01793 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01794 return;
01795 }
01796 if (option_debug > 2)
01797 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01798
01799 snprintf (arg, sizeof(arg), "%lu", messageNum);
01800 ast_mutex_lock(&vms->lock);
01801 mail_setflag (vms->mailstream, arg, "\\DELETED");
01802 mail_expunge(vms->mailstream);
01803 ast_mutex_unlock(&vms->lock);
01804 }
01805
01806 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01807 {
01808 struct vm_state *vms_p;
01809 char *file, *filename;
01810 char *attachment;
01811 int i;
01812 BODY *body;
01813
01814
01815
01816
01817 if (msgnum > -1 || !imapgreetings) {
01818 return 0;
01819 } else {
01820 file = strrchr(ast_strdupa(dir), '/');
01821 if (file)
01822 *file++ = '\0';
01823 else {
01824 ast_debug (1, "Failed to procure file name from directory passed.\n");
01825 return -1;
01826 }
01827 }
01828
01829
01830 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01831 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01832
01833
01834
01835
01836 if (!(vms_p = create_vm_state_from_user(vmu))) {
01837 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01838 return -1;
01839 }
01840 }
01841
01842
01843 *vms_p->introfn = '\0';
01844
01845 ast_mutex_lock(&vms_p->lock);
01846 init_mailstream(vms_p, GREETINGS_FOLDER);
01847 if (!vms_p->mailstream) {
01848 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01849 ast_mutex_unlock(&vms_p->lock);
01850 return -1;
01851 }
01852
01853
01854 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01855 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01856
01857 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01858 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01859 } else {
01860 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01861 ast_mutex_unlock(&vms_p->lock);
01862 return -1;
01863 }
01864 filename = strsep(&attachment, ".");
01865 if (!strcmp(filename, file)) {
01866 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01867 vms_p->msgArray[vms_p->curmsg] = i + 1;
01868 save_body(body, vms_p, "2", attachment, 0);
01869 ast_mutex_unlock(&vms_p->lock);
01870 return 0;
01871 }
01872 }
01873 ast_mutex_unlock(&vms_p->lock);
01874
01875 return -1;
01876 }
01877
01878 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01879 {
01880 BODY *body;
01881 char *header_content;
01882 char *attachedfilefmt;
01883 char buf[80];
01884 struct vm_state *vms;
01885 char text_file[PATH_MAX];
01886 FILE *text_file_ptr;
01887 int res = 0;
01888 struct ast_vm_user *vmu;
01889
01890 if (!(vmu = find_user(NULL, context, mailbox))) {
01891 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01892 return -1;
01893 }
01894
01895 if (msgnum < 0) {
01896 if (imapgreetings) {
01897 res = imap_retrieve_greeting(dir, msgnum, vmu);
01898 goto exit;
01899 } else {
01900 res = 0;
01901 goto exit;
01902 }
01903 }
01904
01905
01906
01907
01908 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01909
01910
01911
01912
01913
01914
01915
01916 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01917 res = -1;
01918 goto exit;
01919 }
01920
01921 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01922 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01923
01924
01925 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01926 res = 0;
01927 goto exit;
01928 }
01929
01930 if (option_debug > 2)
01931 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01932 if (vms->msgArray[msgnum] == 0) {
01933 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01934 res = -1;
01935 goto exit;
01936 }
01937
01938
01939 ast_mutex_lock(&vms->lock);
01940 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01941 ast_mutex_unlock(&vms->lock);
01942
01943 if (ast_strlen_zero(header_content)) {
01944 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01945 res = -1;
01946 goto exit;
01947 }
01948
01949 ast_mutex_lock(&vms->lock);
01950 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01951 ast_mutex_unlock(&vms->lock);
01952
01953
01954 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01955 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01956 } else {
01957 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01958 res = -1;
01959 goto exit;
01960 }
01961
01962
01963
01964 strsep(&attachedfilefmt, ".");
01965 if (!attachedfilefmt) {
01966 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01967 res = -1;
01968 goto exit;
01969 }
01970
01971 save_body(body, vms, "2", attachedfilefmt, 0);
01972 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01973 *vms->introfn = '\0';
01974 }
01975
01976
01977 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01978
01979 if (!(text_file_ptr = fopen(text_file, "w"))) {
01980 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01981 }
01982
01983 fprintf(text_file_ptr, "%s\n", "[message]");
01984
01985 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01986 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01987 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01988 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01989 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01990 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
01991 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
01992 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
01993 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
01994 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
01995 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
01996 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
01997 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
01998 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
01999 fclose(text_file_ptr);
02000
02001 exit:
02002 free_user(vmu);
02003 return res;
02004 }
02005
02006 static int folder_int(const char *folder)
02007 {
02008
02009 if (!folder) {
02010 return 0;
02011 }
02012 if (!strcasecmp(folder, imapfolder)) {
02013 return 0;
02014 } else if (!strcasecmp(folder, "Old")) {
02015 return 1;
02016 } else if (!strcasecmp(folder, "Work")) {
02017 return 2;
02018 } else if (!strcasecmp(folder, "Family")) {
02019 return 3;
02020 } else if (!strcasecmp(folder, "Friends")) {
02021 return 4;
02022 } else if (!strcasecmp(folder, "Cust1")) {
02023 return 5;
02024 } else if (!strcasecmp(folder, "Cust2")) {
02025 return 6;
02026 } else if (!strcasecmp(folder, "Cust3")) {
02027 return 7;
02028 } else if (!strcasecmp(folder, "Cust4")) {
02029 return 8;
02030 } else if (!strcasecmp(folder, "Cust5")) {
02031 return 9;
02032 } else if (!strcasecmp(folder, "Urgent")) {
02033 return 11;
02034 } else {
02035 return 0;
02036 }
02037 }
02038
02039 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02040 {
02041 SEARCHPGM *pgm;
02042 SEARCHHEADER *hdr;
02043
02044 struct ast_vm_user *vmu, vmus;
02045 struct vm_state *vms_p;
02046 int ret = 0;
02047 int fold = folder_int(folder);
02048 int urgent = 0;
02049
02050
02051 if (fold == 11) {
02052 fold = NEW_FOLDER;
02053 urgent = 1;
02054 }
02055
02056 if (ast_strlen_zero(mailbox))
02057 return 0;
02058
02059
02060 vmu = find_user(&vmus, context, mailbox);
02061 if (!vmu) {
02062 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02063 return -1;
02064 } else {
02065
02066 if (vmu->imapuser[0] == '\0') {
02067 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02068 return -1;
02069 }
02070 }
02071
02072
02073 if (vmu->imapuser[0] == '\0') {
02074 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02075 free_user(vmu);
02076 return -1;
02077 }
02078
02079
02080 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02081 if (!vms_p) {
02082 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02083 }
02084 if (vms_p) {
02085 ast_debug(3, "Returning before search - user is logged in\n");
02086 if (fold == 0) {
02087 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02088 }
02089 if (fold == 1) {
02090 return vms_p->oldmessages;
02091 }
02092 }
02093
02094
02095 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02096 if (!vms_p) {
02097 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02098 }
02099
02100 if (!vms_p) {
02101 vms_p = create_vm_state_from_user(vmu);
02102 }
02103 ret = init_mailstream(vms_p, fold);
02104 if (!vms_p->mailstream) {
02105 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02106 return -1;
02107 }
02108 if (ret == 0) {
02109 ast_mutex_lock(&vms_p->lock);
02110 pgm = mail_newsearchpgm ();
02111 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02112 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02113 pgm->header = hdr;
02114 if (fold != OLD_FOLDER) {
02115 pgm->unseen = 1;
02116 pgm->seen = 0;
02117 }
02118
02119
02120
02121 else {
02122 pgm->unseen = 0;
02123 pgm->seen = 1;
02124 }
02125
02126 if (fold == NEW_FOLDER) {
02127 if (urgent) {
02128 pgm->flagged = 1;
02129 pgm->unflagged = 0;
02130 } else {
02131 pgm->flagged = 0;
02132 pgm->unflagged = 1;
02133 }
02134 }
02135 pgm->undeleted = 1;
02136 pgm->deleted = 0;
02137
02138 vms_p->vmArrayIndex = 0;
02139 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02140 if (fold == 0 && urgent == 0)
02141 vms_p->newmessages = vms_p->vmArrayIndex;
02142 if (fold == 1)
02143 vms_p->oldmessages = vms_p->vmArrayIndex;
02144 if (fold == 0 && urgent == 1)
02145 vms_p->urgentmessages = vms_p->vmArrayIndex;
02146
02147 mail_free_searchpgm(&pgm);
02148 ast_mutex_unlock(&vms_p->lock);
02149 vms_p->updated = 0;
02150 return vms_p->vmArrayIndex;
02151 } else {
02152 ast_mutex_lock(&vms_p->lock);
02153 mail_ping(vms_p->mailstream);
02154 ast_mutex_unlock(&vms_p->lock);
02155 }
02156 return 0;
02157 }
02158
02159 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02160 {
02161
02162 check_quota(vms, vmu->imapfolder);
02163 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02164 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02165 ast_play_and_wait(chan, "vm-mailboxfull");
02166 return -1;
02167 }
02168
02169
02170 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));
02171 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02172 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02173 ast_play_and_wait(chan, "vm-mailboxfull");
02174 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02175 return -1;
02176 }
02177
02178 return 0;
02179 }
02180
02181
02182
02183
02184
02185
02186
02187
02188
02189
02190 static int messagecount(const char *context, const char *mailbox, const char *folder)
02191 {
02192 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02193 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02194 } else {
02195 return __messagecount(context, mailbox, folder);
02196 }
02197 }
02198
02199 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)
02200 {
02201 char *myserveremail = serveremail;
02202 char fn[PATH_MAX];
02203 char introfn[PATH_MAX];
02204 char mailbox[256];
02205 char *stringp;
02206 FILE *p = NULL;
02207 char tmp[80] = "/tmp/astmail-XXXXXX";
02208 long len;
02209 void *buf;
02210 int tempcopy = 0;
02211 STRING str;
02212 int ret;
02213 char *imap_flags = NIL;
02214 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02215 int box = NEW_FOLDER;
02216
02217
02218 if (msgnum < 0) {
02219 if(!imapgreetings) {
02220 return 0;
02221 } else {
02222 box = GREETINGS_FOLDER;
02223 }
02224 }
02225
02226 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02227 return -1;
02228 }
02229
02230
02231 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02232 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02233 imap_flags = "\\FLAGGED";
02234 }
02235
02236
02237 fmt = ast_strdupa(fmt);
02238 stringp = fmt;
02239 strsep(&stringp, "|");
02240
02241 if (!ast_strlen_zero(vmu->serveremail))
02242 myserveremail = vmu->serveremail;
02243
02244 if (msgnum > -1)
02245 make_file(fn, sizeof(fn), dir, msgnum);
02246 else
02247 ast_copy_string (fn, dir, sizeof(fn));
02248
02249 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02250 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02251 *introfn = '\0';
02252 }
02253
02254 if (ast_strlen_zero(vmu->email)) {
02255
02256
02257
02258
02259
02260 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02261 tempcopy = 1;
02262 }
02263
02264 if (!strcmp(fmt, "wav49"))
02265 fmt = "WAV";
02266 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02267
02268
02269
02270 if (!(p = vm_mkftemp(tmp))) {
02271 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02272 if (tempcopy)
02273 *(vmu->email) = '\0';
02274 return -1;
02275 }
02276
02277 if (msgnum < 0 && imapgreetings) {
02278 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02279 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02280 return -1;
02281 }
02282 imap_delete_old_greeting(fn, vms);
02283 }
02284
02285 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02286 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02287 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02288 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02289
02290 len = ftell(p);
02291 rewind(p);
02292 if (!(buf = ast_malloc(len + 1))) {
02293 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02294 fclose(p);
02295 if (tempcopy)
02296 *(vmu->email) = '\0';
02297 return -1;
02298 }
02299 if (fread(buf, len, 1, p) < len) {
02300 if (ferror(p)) {
02301 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02302 return -1;
02303 }
02304 }
02305 ((char *) buf)[len] = '\0';
02306 INIT(&str, mail_string, buf, len);
02307 ret = init_mailstream(vms, box);
02308 if (ret == 0) {
02309 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02310 ast_mutex_lock(&vms->lock);
02311 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02312 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02313 ast_mutex_unlock(&vms->lock);
02314 fclose(p);
02315 unlink(tmp);
02316 ast_free(buf);
02317 } else {
02318 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02319 fclose(p);
02320 unlink(tmp);
02321 ast_free(buf);
02322 return -1;
02323 }
02324 ast_debug(3, "%s stored\n", fn);
02325
02326 if (tempcopy)
02327 *(vmu->email) = '\0';
02328 inprocess_count(vmu->mailbox, vmu->context, -1);
02329 return 0;
02330
02331 }
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341
02342
02343
02344
02345
02346 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02347 {
02348 char tmp[PATH_MAX] = "";
02349 char *mailboxnc;
02350 char *context;
02351 char *mb;
02352 char *cur;
02353 if (newmsgs)
02354 *newmsgs = 0;
02355 if (oldmsgs)
02356 *oldmsgs = 0;
02357 if (urgentmsgs)
02358 *urgentmsgs = 0;
02359
02360 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02361
02362 if (ast_strlen_zero(mailbox_context))
02363 return 0;
02364
02365 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02366 context = strchr(tmp, '@');
02367 if (strchr(mailbox_context, ',')) {
02368 int tmpnew, tmpold, tmpurgent;
02369 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02370 mb = tmp;
02371 while ((cur = strsep(&mb, ", "))) {
02372 if (!ast_strlen_zero(cur)) {
02373 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02374 return -1;
02375 else {
02376 if (newmsgs)
02377 *newmsgs += tmpnew;
02378 if (oldmsgs)
02379 *oldmsgs += tmpold;
02380 if (urgentmsgs)
02381 *urgentmsgs += tmpurgent;
02382 }
02383 }
02384 }
02385 return 0;
02386 }
02387 if (context) {
02388 *context = '\0';
02389 mailboxnc = tmp;
02390 context++;
02391 } else {
02392 context = "default";
02393 mailboxnc = (char *) mailbox_context;
02394 }
02395
02396 if (newmsgs) {
02397 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02398 if (!vmu) {
02399 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02400 return -1;
02401 }
02402 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02403 free_user(vmu);
02404 return -1;
02405 }
02406 free_user(vmu);
02407 }
02408 if (oldmsgs) {
02409 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02410 return -1;
02411 }
02412 }
02413 if (urgentmsgs) {
02414 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02415 return -1;
02416 }
02417 }
02418 return 0;
02419 }
02420
02421
02422
02423
02424
02425
02426
02427
02428
02429
02430
02431 static int has_voicemail(const char *mailbox, const char *folder)
02432 {
02433 char tmp[256], *tmp2, *box, *context;
02434 ast_copy_string(tmp, mailbox, sizeof(tmp));
02435 tmp2 = tmp;
02436 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02437 while ((box = strsep(&tmp2, ",&"))) {
02438 if (!ast_strlen_zero(box)) {
02439 if (has_voicemail(box, folder)) {
02440 return 1;
02441 }
02442 }
02443 }
02444 }
02445 if ((context = strchr(tmp, '@'))) {
02446 *context++ = '\0';
02447 } else {
02448 context = "default";
02449 }
02450 return __messagecount(context, tmp, folder) ? 1 : 0;
02451 }
02452
02453
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468 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)
02469 {
02470 struct vm_state *sendvms = NULL, *destvms = NULL;
02471 char messagestring[10];
02472 if (msgnum >= recip->maxmsg) {
02473 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02474 return -1;
02475 }
02476 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02477 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02478 return -1;
02479 }
02480 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02481 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02482 return -1;
02483 }
02484 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02485 ast_mutex_lock(&sendvms->lock);
02486 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02487 ast_mutex_unlock(&sendvms->lock);
02488 return 0;
02489 }
02490 ast_mutex_unlock(&sendvms->lock);
02491 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02492 return -1;
02493 }
02494
02495 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02496 {
02497 char tmp[256], *t = tmp;
02498 size_t left = sizeof(tmp);
02499
02500 if (box == OLD_FOLDER) {
02501 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02502 } else {
02503 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02504 }
02505
02506 if (box == NEW_FOLDER) {
02507 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02508 } else {
02509 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02510 }
02511
02512
02513 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02514
02515
02516 if (!ast_strlen_zero(authuser))
02517 ast_build_string(&t, &left, "/authuser=%s", authuser);
02518
02519
02520 if (!ast_strlen_zero(imapflags))
02521 ast_build_string(&t, &left, "/%s", imapflags);
02522
02523
02524 #if 1
02525 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02526 #else
02527 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02528 #endif
02529 if (box == NEW_FOLDER || box == OLD_FOLDER)
02530 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02531 else if (box == GREETINGS_FOLDER)
02532 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02533 else {
02534 if (!ast_strlen_zero(imapparentfolder)) {
02535
02536 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02537 } else {
02538 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02539 }
02540 }
02541 }
02542
02543 static int init_mailstream(struct vm_state *vms, int box)
02544 {
02545 MAILSTREAM *stream = NIL;
02546 long debug;
02547 char tmp[256];
02548
02549 if (!vms) {
02550 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02551 return -1;
02552 }
02553 if (option_debug > 2)
02554 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02555 if (vms->mailstream == NIL || !vms->mailstream) {
02556 if (option_debug)
02557 ast_log(LOG_DEBUG, "mailstream not set.\n");
02558 } else {
02559 stream = vms->mailstream;
02560 }
02561
02562 debug = NIL;
02563
02564 if (delimiter == '\0') {
02565 char *cp;
02566 #ifdef USE_SYSTEM_IMAP
02567 #include <imap/linkage.c>
02568 #elif defined(USE_SYSTEM_CCLIENT)
02569 #include <c-client/linkage.c>
02570 #else
02571 #include "linkage.c"
02572 #endif
02573
02574 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02575 ast_mutex_lock(&vms->lock);
02576 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02577 ast_mutex_unlock(&vms->lock);
02578 if (stream == NIL) {
02579 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02580 return -1;
02581 }
02582 get_mailbox_delimiter(stream);
02583
02584 for (cp = vms->imapfolder; *cp; cp++)
02585 if (*cp == '/')
02586 *cp = delimiter;
02587 }
02588
02589 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02590 if (option_debug > 2)
02591 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02592 ast_mutex_lock(&vms->lock);
02593 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02594 ast_mutex_unlock(&vms->lock);
02595 if (vms->mailstream == NIL) {
02596 return -1;
02597 } else {
02598 return 0;
02599 }
02600 }
02601
02602 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02603 {
02604 SEARCHPGM *pgm;
02605 SEARCHHEADER *hdr;
02606 int ret, urgent = 0;
02607
02608
02609 if (box == 11) {
02610 box = NEW_FOLDER;
02611 urgent = 1;
02612 }
02613
02614 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02615 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02616 vms->imapversion = vmu->imapversion;
02617 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02618
02619 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02620 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02621 return -1;
02622 }
02623
02624 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02625
02626
02627 if (box == 0) {
02628 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02629 check_quota(vms, (char *) mbox(vmu, box));
02630 }
02631
02632 ast_mutex_lock(&vms->lock);
02633 pgm = mail_newsearchpgm();
02634
02635
02636 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02637 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02638 pgm->header = hdr;
02639 pgm->deleted = 0;
02640 pgm->undeleted = 1;
02641
02642
02643 if (box == NEW_FOLDER && urgent == 1) {
02644 pgm->unseen = 1;
02645 pgm->seen = 0;
02646 pgm->flagged = 1;
02647 pgm->unflagged = 0;
02648 } else if (box == NEW_FOLDER && urgent == 0) {
02649 pgm->unseen = 1;
02650 pgm->seen = 0;
02651 pgm->flagged = 0;
02652 pgm->unflagged = 1;
02653 } else if (box == OLD_FOLDER) {
02654 pgm->seen = 1;
02655 pgm->unseen = 0;
02656 }
02657
02658 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02659
02660 vms->vmArrayIndex = 0;
02661 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02662 vms->lastmsg = vms->vmArrayIndex - 1;
02663 mail_free_searchpgm(&pgm);
02664
02665
02666
02667
02668 if (box == 0 && !vms->dh_arraysize) {
02669 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02670 }
02671 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02672 ast_mutex_unlock(&vms->lock);
02673 return -1;
02674 }
02675
02676 ast_mutex_unlock(&vms->lock);
02677 return 0;
02678 }
02679
02680 static void write_file(char *filename, char *buffer, unsigned long len)
02681 {
02682 FILE *output;
02683
02684 output = fopen (filename, "w");
02685 if (fwrite(buffer, len, 1, output) != 1) {
02686 if (ferror(output)) {
02687 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02688 }
02689 }
02690 fclose (output);
02691 }
02692
02693 static void update_messages_by_imapuser(const char *user, unsigned long number)
02694 {
02695 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02696
02697 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02698 return;
02699 }
02700
02701 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02702 vms->msgArray[vms->vmArrayIndex++] = number;
02703 }
02704
02705 void mm_searched(MAILSTREAM *stream, unsigned long number)
02706 {
02707 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02708
02709 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02710 return;
02711
02712 update_messages_by_imapuser(user, number);
02713 }
02714
02715 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02716 {
02717 struct ast_variable *var;
02718 struct ast_vm_user *vmu;
02719
02720 vmu = ast_calloc(1, sizeof *vmu);
02721 if (!vmu)
02722 return NULL;
02723
02724 populate_defaults(vmu);
02725 ast_set_flag(vmu, VM_ALLOCED);
02726
02727 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02728 if (var) {
02729 apply_options_full(vmu, var);
02730 ast_variables_destroy(var);
02731 return vmu;
02732 } else {
02733 ast_free(vmu);
02734 return NULL;
02735 }
02736 }
02737
02738
02739
02740 void mm_exists(MAILSTREAM * stream, unsigned long number)
02741 {
02742
02743 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02744 if (number == 0) return;
02745 set_update(stream);
02746 }
02747
02748
02749 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02750 {
02751
02752 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02753 if (number == 0) return;
02754 set_update(stream);
02755 }
02756
02757
02758 void mm_flags(MAILSTREAM * stream, unsigned long number)
02759 {
02760
02761 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02762 if (number == 0) return;
02763 set_update(stream);
02764 }
02765
02766
02767 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02768 {
02769 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02770 mm_log (string, errflg);
02771 }
02772
02773
02774 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02775 {
02776 if (delimiter == '\0') {
02777 delimiter = delim;
02778 }
02779
02780 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02781 if (attributes & LATT_NOINFERIORS)
02782 ast_debug(5, "no inferiors\n");
02783 if (attributes & LATT_NOSELECT)
02784 ast_debug(5, "no select\n");
02785 if (attributes & LATT_MARKED)
02786 ast_debug(5, "marked\n");
02787 if (attributes & LATT_UNMARKED)
02788 ast_debug(5, "unmarked\n");
02789 }
02790
02791
02792 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02793 {
02794 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02795 if (attributes & LATT_NOINFERIORS)
02796 ast_debug(5, "no inferiors\n");
02797 if (attributes & LATT_NOSELECT)
02798 ast_debug(5, "no select\n");
02799 if (attributes & LATT_MARKED)
02800 ast_debug(5, "marked\n");
02801 if (attributes & LATT_UNMARKED)
02802 ast_debug(5, "unmarked\n");
02803 }
02804
02805
02806 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02807 {
02808 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02809 if (status->flags & SA_MESSAGES)
02810 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02811 if (status->flags & SA_RECENT)
02812 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02813 if (status->flags & SA_UNSEEN)
02814 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02815 if (status->flags & SA_UIDVALIDITY)
02816 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02817 if (status->flags & SA_UIDNEXT)
02818 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02819 ast_log(AST_LOG_NOTICE, "\n");
02820 }
02821
02822
02823 void mm_log(char *string, long errflg)
02824 {
02825 switch ((short) errflg) {
02826 case NIL:
02827 ast_debug(1, "IMAP Info: %s\n", string);
02828 break;
02829 case PARSE:
02830 case WARN:
02831 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02832 break;
02833 case ERROR:
02834 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02835 break;
02836 }
02837 }
02838
02839
02840 void mm_dlog(char *string)
02841 {
02842 ast_log(AST_LOG_NOTICE, "%s\n", string);
02843 }
02844
02845
02846 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02847 {
02848 struct ast_vm_user *vmu;
02849
02850 ast_debug(4, "Entering callback mm_login\n");
02851
02852 ast_copy_string(user, mb->user, MAILTMPLEN);
02853
02854
02855 if (!ast_strlen_zero(authpassword)) {
02856 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02857 } else {
02858 AST_LIST_TRAVERSE(&users, vmu, list) {
02859 if (!strcasecmp(mb->user, vmu->imapuser)) {
02860 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02861 break;
02862 }
02863 }
02864 if (!vmu) {
02865 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02866 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02867 free_user(vmu);
02868 }
02869 }
02870 }
02871 }
02872
02873
02874 void mm_critical(MAILSTREAM * stream)
02875 {
02876 }
02877
02878
02879 void mm_nocritical(MAILSTREAM * stream)
02880 {
02881 }
02882
02883
02884 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02885 {
02886 kill (getpid (), SIGSTOP);
02887 return NIL;
02888 }
02889
02890
02891 void mm_fatal(char *string)
02892 {
02893 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02894 }
02895
02896
02897 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02898 {
02899 struct vm_state *vms;
02900 char *mailbox = stream->mailbox, *user;
02901 char buf[1024] = "";
02902 unsigned long usage = 0, limit = 0;
02903
02904 while (pquota) {
02905 usage = pquota->usage;
02906 limit = pquota->limit;
02907 pquota = pquota->next;
02908 }
02909
02910 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)))) {
02911 ast_log(AST_LOG_ERROR, "No state found.\n");
02912 return;
02913 }
02914
02915 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02916
02917 vms->quota_usage = usage;
02918 vms->quota_limit = limit;
02919 }
02920
02921 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02922 {
02923 char *start, *eol_pnt;
02924 int taglen;
02925
02926 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02927 return NULL;
02928
02929 taglen = strlen(tag) + 1;
02930 if (taglen < 1)
02931 return NULL;
02932
02933 if (!(start = strstr(header, tag)))
02934 return NULL;
02935
02936
02937 memset(buf, 0, len);
02938
02939 ast_copy_string(buf, start+taglen, len);
02940 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02941 *eol_pnt = '\0';
02942 return buf;
02943 }
02944
02945 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02946 {
02947 char *start, *quote, *eol_pnt;
02948
02949 if (ast_strlen_zero(mailbox))
02950 return NULL;
02951
02952 if (!(start = strstr(mailbox, "/user=")))
02953 return NULL;
02954
02955 ast_copy_string(buf, start+6, len);
02956
02957 if (!(quote = strchr(buf, '\"'))) {
02958 if (!(eol_pnt = strchr(buf, '/')))
02959 eol_pnt = strchr(buf,'}');
02960 *eol_pnt = '\0';
02961 return buf;
02962 } else {
02963 eol_pnt = strchr(buf+1,'\"');
02964 *eol_pnt = '\0';
02965 return buf+1;
02966 }
02967 }
02968
02969 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02970 {
02971 struct vm_state *vms_p;
02972
02973 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02974 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02975 return vms_p;
02976 }
02977 if (option_debug > 4)
02978 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02979 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02980 return NULL;
02981 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02982 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
02983 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02984 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02985 vms_p->mailstream = NIL;
02986 vms_p->imapversion = vmu->imapversion;
02987 if (option_debug > 4)
02988 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
02989 vms_p->updated = 1;
02990
02991 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
02992 init_vm_state(vms_p);
02993 vmstate_insert(vms_p);
02994 return vms_p;
02995 }
02996
02997 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
02998 {
02999 struct vmstate *vlist = NULL;
03000
03001 if (interactive) {
03002 struct vm_state *vms;
03003 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03004 vms = pthread_getspecific(ts_vmstate.key);
03005 return vms;
03006 }
03007
03008 AST_LIST_LOCK(&vmstates);
03009 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03010 if (!vlist->vms) {
03011 ast_debug(3, "error: vms is NULL for %s\n", user);
03012 continue;
03013 }
03014 if (vlist->vms->imapversion != imapversion) {
03015 continue;
03016 }
03017 if (!vlist->vms->imapuser) {
03018 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03019 continue;
03020 }
03021
03022 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03023 AST_LIST_UNLOCK(&vmstates);
03024 return vlist->vms;
03025 }
03026 }
03027 AST_LIST_UNLOCK(&vmstates);
03028
03029 ast_debug(3, "%s not found in vmstates\n", user);
03030
03031 return NULL;
03032 }
03033
03034 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03035 {
03036
03037 struct vmstate *vlist = NULL;
03038 const char *local_context = S_OR(context, "default");
03039
03040 if (interactive) {
03041 struct vm_state *vms;
03042 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03043 vms = pthread_getspecific(ts_vmstate.key);
03044 return vms;
03045 }
03046
03047 AST_LIST_LOCK(&vmstates);
03048 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03049 if (!vlist->vms) {
03050 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03051 continue;
03052 }
03053 if (vlist->vms->imapversion != imapversion) {
03054 continue;
03055 }
03056 if (!vlist->vms->username || !vlist->vms->context) {
03057 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03058 continue;
03059 }
03060
03061 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);
03062
03063 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03064 ast_debug(3, "Found it!\n");
03065 AST_LIST_UNLOCK(&vmstates);
03066 return vlist->vms;
03067 }
03068 }
03069 AST_LIST_UNLOCK(&vmstates);
03070
03071 ast_debug(3, "%s not found in vmstates\n", mailbox);
03072
03073 return NULL;
03074 }
03075
03076 static void vmstate_insert(struct vm_state *vms)
03077 {
03078 struct vmstate *v;
03079 struct vm_state *altvms;
03080
03081
03082
03083
03084 if (vms->interactive == 1) {
03085 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03086 if (altvms) {
03087 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03088 vms->newmessages = altvms->newmessages;
03089 vms->oldmessages = altvms->oldmessages;
03090 vms->vmArrayIndex = altvms->vmArrayIndex;
03091 vms->lastmsg = altvms->lastmsg;
03092 vms->curmsg = altvms->curmsg;
03093
03094 vms->persist_vms = altvms;
03095
03096 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03097 vms->mailstream = altvms->mailstream;
03098 #else
03099 vms->mailstream = NIL;
03100 #endif
03101 }
03102 return;
03103 }
03104
03105 if (!(v = ast_calloc(1, sizeof(*v))))
03106 return;
03107
03108 v->vms = vms;
03109
03110 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03111
03112 AST_LIST_LOCK(&vmstates);
03113 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03114 AST_LIST_UNLOCK(&vmstates);
03115 }
03116
03117 static void vmstate_delete(struct vm_state *vms)
03118 {
03119 struct vmstate *vc = NULL;
03120 struct vm_state *altvms = NULL;
03121
03122
03123
03124 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03125 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03126 altvms->newmessages = vms->newmessages;
03127 altvms->oldmessages = vms->oldmessages;
03128 altvms->updated = 1;
03129 vms->mailstream = mail_close(vms->mailstream);
03130
03131
03132 return;
03133 }
03134
03135 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03136
03137 AST_LIST_LOCK(&vmstates);
03138 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03139 if (vc->vms == vms) {
03140 AST_LIST_REMOVE_CURRENT(list);
03141 break;
03142 }
03143 }
03144 AST_LIST_TRAVERSE_SAFE_END
03145 AST_LIST_UNLOCK(&vmstates);
03146
03147 if (vc) {
03148 ast_mutex_destroy(&vc->vms->lock);
03149 ast_free(vc);
03150 }
03151 else
03152 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03153 }
03154
03155 static void set_update(MAILSTREAM * stream)
03156 {
03157 struct vm_state *vms;
03158 char *mailbox = stream->mailbox, *user;
03159 char buf[1024] = "";
03160
03161 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03162 if (user && option_debug > 2)
03163 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03164 return;
03165 }
03166
03167 ast_debug(3, "User %s mailbox set for update.\n", user);
03168
03169 vms->updated = 1;
03170 }
03171
03172 static void init_vm_state(struct vm_state *vms)
03173 {
03174 int x;
03175 vms->vmArrayIndex = 0;
03176 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03177 vms->msgArray[x] = 0;
03178 }
03179 ast_mutex_init(&vms->lock);
03180 }
03181
03182 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03183 {
03184 char *body_content;
03185 char *body_decoded;
03186 char *fn = is_intro ? vms->introfn : vms->fn;
03187 unsigned long len;
03188 unsigned long newlen;
03189 char filename[256];
03190
03191 if (!body || body == NIL)
03192 return -1;
03193
03194 ast_mutex_lock(&vms->lock);
03195 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03196 ast_mutex_unlock(&vms->lock);
03197 if (body_content != NIL) {
03198 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03199
03200 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03201
03202 if (!newlen) {
03203 return -1;
03204 }
03205 write_file(filename, (char *) body_decoded, newlen);
03206 } else {
03207 ast_debug(5, "Body of message is NULL.\n");
03208 return -1;
03209 }
03210 return 0;
03211 }
03212
03213
03214
03215
03216
03217
03218
03219
03220 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03221 char tmp[50];
03222 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03223 mail_list(stream, tmp, "*");
03224 }
03225
03226
03227
03228
03229
03230
03231
03232
03233 static void check_quota(struct vm_state *vms, char *mailbox) {
03234 ast_mutex_lock(&vms->lock);
03235 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03236 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03237 if (vms && vms->mailstream != NULL) {
03238 imap_getquotaroot(vms->mailstream, mailbox);
03239 } else {
03240 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03241 }
03242 ast_mutex_unlock(&vms->lock);
03243 }
03244
03245 #endif
03246
03247
03248
03249
03250
03251 static int vm_lock_path(const char *path)
03252 {
03253 switch (ast_lock_path(path)) {
03254 case AST_LOCK_TIMEOUT:
03255 return -1;
03256 default:
03257 return 0;
03258 }
03259 }
03260
03261
03262 #ifdef ODBC_STORAGE
03263 struct generic_prepare_struct {
03264 char *sql;
03265 int argc;
03266 char **argv;
03267 };
03268
03269 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03270 {
03271 struct generic_prepare_struct *gps = data;
03272 int res, i;
03273 SQLHSTMT stmt;
03274
03275 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03276 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03277 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03278 return NULL;
03279 }
03280 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03281 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03282 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03283 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03284 return NULL;
03285 }
03286 for (i = 0; i < gps->argc; i++)
03287 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03288
03289 return stmt;
03290 }
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306 static int retrieve_file(char *dir, int msgnum)
03307 {
03308 int x = 0;
03309 int res;
03310 int fd = -1;
03311 size_t fdlen = 0;
03312 void *fdm = MAP_FAILED;
03313 SQLSMALLINT colcount = 0;
03314 SQLHSTMT stmt;
03315 char sql[PATH_MAX];
03316 char fmt[80]="";
03317 char *c;
03318 char coltitle[256];
03319 SQLSMALLINT collen;
03320 SQLSMALLINT datatype;
03321 SQLSMALLINT decimaldigits;
03322 SQLSMALLINT nullable;
03323 SQLULEN colsize;
03324 SQLLEN colsize2;
03325 FILE *f = NULL;
03326 char rowdata[80];
03327 char fn[PATH_MAX];
03328 char full_fn[PATH_MAX];
03329 char msgnums[80];
03330 char *argv[] = { dir, msgnums };
03331 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03332
03333 struct odbc_obj *obj;
03334 obj = ast_odbc_request_obj(odbc_database, 0);
03335 if (obj) {
03336 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03337 c = strchr(fmt, '|');
03338 if (c)
03339 *c = '\0';
03340 if (!strcasecmp(fmt, "wav49"))
03341 strcpy(fmt, "WAV");
03342 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03343 if (msgnum > -1)
03344 make_file(fn, sizeof(fn), dir, msgnum);
03345 else
03346 ast_copy_string(fn, dir, sizeof(fn));
03347
03348
03349 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03350
03351 if (!(f = fopen(full_fn, "w+"))) {
03352 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03353 goto yuck;
03354 }
03355
03356 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03357 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03358 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03359 if (!stmt) {
03360 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03361 ast_odbc_release_obj(obj);
03362 goto yuck;
03363 }
03364 res = SQLFetch(stmt);
03365 if (res == SQL_NO_DATA) {
03366 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03367 ast_odbc_release_obj(obj);
03368 goto yuck;
03369 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03370 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03371 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03372 ast_odbc_release_obj(obj);
03373 goto yuck;
03374 }
03375 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03376 if (fd < 0) {
03377 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03378 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03379 ast_odbc_release_obj(obj);
03380 goto yuck;
03381 }
03382 res = SQLNumResultCols(stmt, &colcount);
03383 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03384 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03385 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03386 ast_odbc_release_obj(obj);
03387 goto yuck;
03388 }
03389 if (f)
03390 fprintf(f, "[message]\n");
03391 for (x = 0; x < colcount; x++) {
03392 rowdata[0] = '\0';
03393 colsize = 0;
03394 collen = sizeof(coltitle);
03395 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03396 &datatype, &colsize, &decimaldigits, &nullable);
03397 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03398 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03399 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03400 ast_odbc_release_obj(obj);
03401 goto yuck;
03402 }
03403 if (!strcasecmp(coltitle, "recording")) {
03404 off_t offset;
03405 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03406 fdlen = colsize2;
03407 if (fd > -1) {
03408 char tmp[1]="";
03409 lseek(fd, fdlen - 1, SEEK_SET);
03410 if (write(fd, tmp, 1) != 1) {
03411 close(fd);
03412 fd = -1;
03413 continue;
03414 }
03415
03416 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03417 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03418 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03419 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03420 ast_odbc_release_obj(obj);
03421 goto yuck;
03422 } else {
03423 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03424 munmap(fdm, CHUNKSIZE);
03425 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03426 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03427 unlink(full_fn);
03428 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03429 ast_odbc_release_obj(obj);
03430 goto yuck;
03431 }
03432 }
03433 }
03434 if (truncate(full_fn, fdlen) < 0) {
03435 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03436 }
03437 }
03438 } else {
03439 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03440 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03441 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03442 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03443 ast_odbc_release_obj(obj);
03444 goto yuck;
03445 }
03446 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03447 fprintf(f, "%s=%s\n", coltitle, rowdata);
03448 }
03449 }
03450 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03451 ast_odbc_release_obj(obj);
03452 } else
03453 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03454 yuck:
03455 if (f)
03456 fclose(f);
03457 if (fd > -1)
03458 close(fd);
03459 return x - 1;
03460 }
03461
03462
03463
03464
03465
03466
03467
03468
03469
03470
03471
03472
03473 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03474 {
03475 int x = 0;
03476 int res;
03477 SQLHSTMT stmt;
03478 char sql[PATH_MAX];
03479 char rowdata[20];
03480 char *argv[] = { dir };
03481 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03482
03483 struct odbc_obj *obj;
03484 obj = ast_odbc_request_obj(odbc_database, 0);
03485 if (obj) {
03486 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03487
03488 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03489 if (!stmt) {
03490 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03491 ast_odbc_release_obj(obj);
03492 goto yuck;
03493 }
03494 res = SQLFetch(stmt);
03495 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03496 if (res == SQL_NO_DATA) {
03497 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03498 } else {
03499 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03500 }
03501
03502 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03503 ast_odbc_release_obj(obj);
03504 goto yuck;
03505 }
03506 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03507 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03508 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03509 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03510 ast_odbc_release_obj(obj);
03511 goto yuck;
03512 }
03513 if (sscanf(rowdata, "%30d", &x) != 1)
03514 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03515 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03516 ast_odbc_release_obj(obj);
03517 return x;
03518 } else
03519 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03520 yuck:
03521 return x - 1;
03522 }
03523
03524
03525
03526
03527
03528
03529
03530
03531
03532
03533 static int message_exists(char *dir, int msgnum)
03534 {
03535 int x = 0;
03536 int res;
03537 SQLHSTMT stmt;
03538 char sql[PATH_MAX];
03539 char rowdata[20];
03540 char msgnums[20];
03541 char *argv[] = { dir, msgnums };
03542 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03543
03544 struct odbc_obj *obj;
03545 obj = ast_odbc_request_obj(odbc_database, 0);
03546 if (obj) {
03547 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03548 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03549 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03550 if (!stmt) {
03551 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03552 ast_odbc_release_obj(obj);
03553 goto yuck;
03554 }
03555 res = SQLFetch(stmt);
03556 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03557 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03558 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03559 ast_odbc_release_obj(obj);
03560 goto yuck;
03561 }
03562 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03563 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03564 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03565 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03566 ast_odbc_release_obj(obj);
03567 goto yuck;
03568 }
03569 if (sscanf(rowdata, "%30d", &x) != 1)
03570 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03571 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03572 ast_odbc_release_obj(obj);
03573 } else
03574 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03575 yuck:
03576 return x;
03577 }
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587
03588 static int count_messages(struct ast_vm_user *vmu, char *dir)
03589 {
03590 int x = 0;
03591 int res;
03592 SQLHSTMT stmt;
03593 char sql[PATH_MAX];
03594 char rowdata[20];
03595 char *argv[] = { dir };
03596 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03597
03598 struct odbc_obj *obj;
03599 obj = ast_odbc_request_obj(odbc_database, 0);
03600 if (obj) {
03601 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03602 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03603 if (!stmt) {
03604 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03605 ast_odbc_release_obj(obj);
03606 goto yuck;
03607 }
03608 res = SQLFetch(stmt);
03609 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03610 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03611 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03612 ast_odbc_release_obj(obj);
03613 goto yuck;
03614 }
03615 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03616 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03617 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03618 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03619 ast_odbc_release_obj(obj);
03620 goto yuck;
03621 }
03622 if (sscanf(rowdata, "%30d", &x) != 1)
03623 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03624 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03625 ast_odbc_release_obj(obj);
03626 return x;
03627 } else
03628 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03629 yuck:
03630 return x - 1;
03631
03632 }
03633
03634
03635
03636
03637
03638
03639
03640
03641
03642
03643
03644 static void delete_file(const char *sdir, int smsg)
03645 {
03646 SQLHSTMT stmt;
03647 char sql[PATH_MAX];
03648 char msgnums[20];
03649 char *argv[] = { NULL, msgnums };
03650 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03651 struct odbc_obj *obj;
03652
03653 argv[0] = ast_strdupa(sdir);
03654
03655 obj = ast_odbc_request_obj(odbc_database, 0);
03656 if (obj) {
03657 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03658 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03659 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03660 if (!stmt)
03661 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03662 else
03663 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03664 ast_odbc_release_obj(obj);
03665 } else
03666 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03667 return;
03668 }
03669
03670
03671
03672
03673
03674
03675
03676
03677
03678
03679
03680
03681 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03682 {
03683 SQLHSTMT stmt;
03684 char sql[512];
03685 char msgnums[20];
03686 char msgnumd[20];
03687 struct odbc_obj *obj;
03688 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03689 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03690
03691 delete_file(ddir, dmsg);
03692 obj = ast_odbc_request_obj(odbc_database, 0);
03693 if (obj) {
03694 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03695 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03696 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);
03697 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03698 if (!stmt)
03699 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03700 else
03701 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03702 ast_odbc_release_obj(obj);
03703 } else
03704 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03705 return;
03706 }
03707
03708 struct insert_data {
03709 char *sql;
03710 const char *dir;
03711 const char *msgnums;
03712 void *data;
03713 SQLLEN datalen;
03714 SQLLEN indlen;
03715 const char *context;
03716 const char *macrocontext;
03717 const char *callerid;
03718 const char *origtime;
03719 const char *duration;
03720 const char *mailboxuser;
03721 const char *mailboxcontext;
03722 const char *category;
03723 const char *flag;
03724 };
03725
03726 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03727 {
03728 struct insert_data *data = vdata;
03729 int res;
03730 SQLHSTMT stmt;
03731
03732 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03733 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03734 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03735 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03736 return NULL;
03737 }
03738
03739 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03740 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03741 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03742 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03743 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03744 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03745 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03746 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03747 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03748 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03749 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03750 if (!ast_strlen_zero(data->category)) {
03751 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03752 }
03753 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03754 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03755 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03756 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03757 return NULL;
03758 }
03759
03760 return stmt;
03761 }
03762
03763
03764
03765
03766
03767
03768
03769
03770
03771
03772
03773
03774
03775
03776 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03777 {
03778 int res = 0;
03779 int fd = -1;
03780 void *fdm = MAP_FAILED;
03781 off_t fdlen = -1;
03782 SQLHSTMT stmt;
03783 char sql[PATH_MAX];
03784 char msgnums[20];
03785 char fn[PATH_MAX];
03786 char full_fn[PATH_MAX];
03787 char fmt[80]="";
03788 char *c;
03789 struct ast_config *cfg = NULL;
03790 struct odbc_obj *obj;
03791 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03792 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03793 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03794
03795 delete_file(dir, msgnum);
03796 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03797 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03798 return -1;
03799 }
03800
03801 do {
03802 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03803 c = strchr(fmt, '|');
03804 if (c)
03805 *c = '\0';
03806 if (!strcasecmp(fmt, "wav49"))
03807 strcpy(fmt, "WAV");
03808 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03809 if (msgnum > -1)
03810 make_file(fn, sizeof(fn), dir, msgnum);
03811 else
03812 ast_copy_string(fn, dir, sizeof(fn));
03813 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03814 cfg = ast_config_load(full_fn, config_flags);
03815 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03816 fd = open(full_fn, O_RDWR);
03817 if (fd < 0) {
03818 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03819 res = -1;
03820 break;
03821 }
03822 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03823 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03824 idata.context = "";
03825 }
03826 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03827 idata.macrocontext = "";
03828 }
03829 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03830 idata.callerid = "";
03831 }
03832 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03833 idata.origtime = "";
03834 }
03835 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03836 idata.duration = "";
03837 }
03838 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03839 idata.category = "";
03840 }
03841 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03842 idata.flag = "";
03843 }
03844 }
03845 fdlen = lseek(fd, 0, SEEK_END);
03846 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03847 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03848 res = -1;
03849 break;
03850 }
03851 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03852 if (fdm == MAP_FAILED) {
03853 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03854 res = -1;
03855 break;
03856 }
03857 idata.data = fdm;
03858 idata.datalen = idata.indlen = fdlen;
03859
03860 if (!ast_strlen_zero(idata.category))
03861 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03862 else
03863 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03864
03865 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03866 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03867 } else {
03868 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03869 res = -1;
03870 }
03871 } while (0);
03872 if (obj) {
03873 ast_odbc_release_obj(obj);
03874 }
03875 if (cfg)
03876 ast_config_destroy(cfg);
03877 if (fdm != MAP_FAILED)
03878 munmap(fdm, fdlen);
03879 if (fd > -1)
03880 close(fd);
03881 return res;
03882 }
03883
03884
03885
03886
03887
03888
03889
03890
03891
03892
03893
03894
03895
03896
03897 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03898 {
03899 SQLHSTMT stmt;
03900 char sql[PATH_MAX];
03901 char msgnums[20];
03902 char msgnumd[20];
03903 struct odbc_obj *obj;
03904 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03905 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03906
03907 delete_file(ddir, dmsg);
03908 obj = ast_odbc_request_obj(odbc_database, 0);
03909 if (obj) {
03910 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03911 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03912 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03913 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03914 if (!stmt)
03915 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03916 else
03917 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03918 ast_odbc_release_obj(obj);
03919 } else
03920 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03921 return;
03922 }
03923
03924
03925
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935 static int remove_file(char *dir, int msgnum)
03936 {
03937 char fn[PATH_MAX];
03938 char full_fn[PATH_MAX];
03939 char msgnums[80];
03940
03941 if (msgnum > -1) {
03942 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03943 make_file(fn, sizeof(fn), dir, msgnum);
03944 } else
03945 ast_copy_string(fn, dir, sizeof(fn));
03946 ast_filedelete(fn, NULL);
03947 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03948 unlink(full_fn);
03949 return 0;
03950 }
03951 #else
03952 #ifndef IMAP_STORAGE
03953
03954
03955
03956
03957
03958
03959
03960
03961
03962 static int count_messages(struct ast_vm_user *vmu, char *dir)
03963 {
03964
03965 int vmcount = 0;
03966 DIR *vmdir = NULL;
03967 struct dirent *vment = NULL;
03968
03969 if (vm_lock_path(dir))
03970 return ERROR_LOCK_PATH;
03971
03972 if ((vmdir = opendir(dir))) {
03973 while ((vment = readdir(vmdir))) {
03974 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03975 vmcount++;
03976 }
03977 }
03978 closedir(vmdir);
03979 }
03980 ast_unlock_path(dir);
03981
03982 return vmcount;
03983 }
03984
03985
03986
03987
03988
03989
03990
03991
03992 static void rename_file(char *sfn, char *dfn)
03993 {
03994 char stxt[PATH_MAX];
03995 char dtxt[PATH_MAX];
03996 ast_filerename(sfn, dfn, NULL);
03997 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
03998 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
03999 if (ast_check_realtime("voicemail_data")) {
04000 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04001 }
04002 rename(stxt, dtxt);
04003 }
04004
04005
04006
04007
04008
04009
04010
04011
04012
04013
04014
04015
04016 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04017 {
04018 int x;
04019 unsigned char map[MAXMSGLIMIT] = "";
04020 DIR *msgdir;
04021 struct dirent *msgdirent;
04022 int msgdirint;
04023 char extension[4];
04024 int stopcount = 0;
04025
04026
04027
04028
04029
04030 if (!(msgdir = opendir(dir))) {
04031 return -1;
04032 }
04033
04034 while ((msgdirent = readdir(msgdir))) {
04035 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04036 map[msgdirint] = 1;
04037 stopcount++;
04038 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04039 }
04040 }
04041 closedir(msgdir);
04042
04043 for (x = 0; x < vmu->maxmsg; x++) {
04044 if (map[x] == 1) {
04045 stopcount--;
04046 } else if (map[x] == 0 && !stopcount) {
04047 break;
04048 }
04049 }
04050
04051 return x - 1;
04052 }
04053
04054 #endif
04055 #endif
04056 #ifndef IMAP_STORAGE
04057
04058
04059
04060
04061
04062
04063
04064
04065
04066
04067 static int copy(char *infile, char *outfile)
04068 {
04069 int ifd;
04070 int ofd;
04071 int res;
04072 int len;
04073 char buf[4096];
04074
04075 #ifdef HARDLINK_WHEN_POSSIBLE
04076
04077 if (link(infile, outfile)) {
04078 #endif
04079 if ((ifd = open(infile, O_RDONLY)) < 0) {
04080 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04081 return -1;
04082 }
04083 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04084 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04085 close(ifd);
04086 return -1;
04087 }
04088 do {
04089 len = read(ifd, buf, sizeof(buf));
04090 if (len < 0) {
04091 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04092 close(ifd);
04093 close(ofd);
04094 unlink(outfile);
04095 } else if (len) {
04096 res = write(ofd, buf, len);
04097 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04098 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04099 close(ifd);
04100 close(ofd);
04101 unlink(outfile);
04102 }
04103 }
04104 } while (len);
04105 close(ifd);
04106 close(ofd);
04107 return 0;
04108 #ifdef HARDLINK_WHEN_POSSIBLE
04109 } else {
04110
04111 return 0;
04112 }
04113 #endif
04114 }
04115
04116
04117
04118
04119
04120
04121
04122
04123
04124
04125 static void copy_plain_file(char *frompath, char *topath)
04126 {
04127 char frompath2[PATH_MAX], topath2[PATH_MAX];
04128 struct ast_variable *tmp,*var = NULL;
04129 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04130 ast_filecopy(frompath, topath, NULL);
04131 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04132 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04133 if (ast_check_realtime("voicemail_data")) {
04134 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04135
04136 for (tmp = var; tmp; tmp = tmp->next) {
04137 if (!strcasecmp(tmp->name, "origmailbox")) {
04138 origmailbox = tmp->value;
04139 } else if (!strcasecmp(tmp->name, "context")) {
04140 context = tmp->value;
04141 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04142 macrocontext = tmp->value;
04143 } else if (!strcasecmp(tmp->name, "exten")) {
04144 exten = tmp->value;
04145 } else if (!strcasecmp(tmp->name, "priority")) {
04146 priority = tmp->value;
04147 } else if (!strcasecmp(tmp->name, "callerchan")) {
04148 callerchan = tmp->value;
04149 } else if (!strcasecmp(tmp->name, "callerid")) {
04150 callerid = tmp->value;
04151 } else if (!strcasecmp(tmp->name, "origdate")) {
04152 origdate = tmp->value;
04153 } else if (!strcasecmp(tmp->name, "origtime")) {
04154 origtime = tmp->value;
04155 } else if (!strcasecmp(tmp->name, "category")) {
04156 category = tmp->value;
04157 } else if (!strcasecmp(tmp->name, "duration")) {
04158 duration = tmp->value;
04159 }
04160 }
04161 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);
04162 }
04163 copy(frompath2, topath2);
04164 ast_variables_destroy(var);
04165 }
04166 #endif
04167
04168
04169
04170
04171
04172
04173
04174
04175
04176 static int vm_delete(char *file)
04177 {
04178 char *txt;
04179 int txtsize = 0;
04180
04181 txtsize = (strlen(file) + 5)*sizeof(char);
04182 txt = ast_alloca(txtsize);
04183
04184
04185
04186 if (ast_check_realtime("voicemail_data")) {
04187 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04188 }
04189 snprintf(txt, txtsize, "%s.txt", file);
04190 unlink(txt);
04191 return ast_filedelete(file, NULL);
04192 }
04193
04194
04195
04196
04197 static int inbuf(struct baseio *bio, FILE *fi)
04198 {
04199 int l;
04200
04201 if (bio->ateof)
04202 return 0;
04203
04204 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04205 if (ferror(fi))
04206 return -1;
04207
04208 bio->ateof = 1;
04209 return 0;
04210 }
04211
04212 bio->iolen = l;
04213 bio->iocp = 0;
04214
04215 return 1;
04216 }
04217
04218
04219
04220
04221 static int inchar(struct baseio *bio, FILE *fi)
04222 {
04223 if (bio->iocp>=bio->iolen) {
04224 if (!inbuf(bio, fi))
04225 return EOF;
04226 }
04227
04228 return bio->iobuf[bio->iocp++];
04229 }
04230
04231
04232
04233
04234 static int ochar(struct baseio *bio, int c, FILE *so)
04235 {
04236 if (bio->linelength >= BASELINELEN) {
04237 if (fputs(ENDL, so) == EOF) {
04238 return -1;
04239 }
04240
04241 bio->linelength = 0;
04242 }
04243
04244 if (putc(((unsigned char) c), so) == EOF) {
04245 return -1;
04246 }
04247
04248 bio->linelength++;
04249
04250 return 1;
04251 }
04252
04253
04254
04255
04256
04257
04258
04259
04260
04261
04262 static int base_encode(char *filename, FILE *so)
04263 {
04264 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04265 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04266 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04267 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04268 int i, hiteof = 0;
04269 FILE *fi;
04270 struct baseio bio;
04271
04272 memset(&bio, 0, sizeof(bio));
04273 bio.iocp = BASEMAXINLINE;
04274
04275 if (!(fi = fopen(filename, "rb"))) {
04276 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04277 return -1;
04278 }
04279
04280 while (!hiteof){
04281 unsigned char igroup[3], ogroup[4];
04282 int c, n;
04283
04284 memset(igroup, 0, sizeof(igroup));
04285
04286 for (n = 0; n < 3; n++) {
04287 if ((c = inchar(&bio, fi)) == EOF) {
04288 hiteof = 1;
04289 break;
04290 }
04291
04292 igroup[n] = (unsigned char) c;
04293 }
04294
04295 if (n > 0) {
04296 ogroup[0]= dtable[igroup[0] >> 2];
04297 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04298 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04299 ogroup[3]= dtable[igroup[2] & 0x3F];
04300
04301 if (n < 3) {
04302 ogroup[3] = '=';
04303
04304 if (n < 2)
04305 ogroup[2] = '=';
04306 }
04307
04308 for (i = 0; i < 4; i++)
04309 ochar(&bio, ogroup[i], so);
04310 }
04311 }
04312
04313 fclose(fi);
04314
04315 if (fputs(ENDL, so) == EOF) {
04316 return 0;
04317 }
04318
04319 return 1;
04320 }
04321
04322 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)
04323 {
04324 char callerid[256];
04325 char num[12];
04326 char fromdir[256], fromfile[256];
04327 struct ast_config *msg_cfg;
04328 const char *origcallerid, *origtime;
04329 char origcidname[80], origcidnum[80], origdate[80];
04330 int inttime;
04331 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04332
04333
04334 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04335 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04336 snprintf(num, sizeof(num), "%d", msgnum);
04337 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04338 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04339 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04340 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04341 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04342 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04343 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04344 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04345 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04346 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04347
04348
04349 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04350 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04351 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04352 strcat(fromfile, ".txt");
04353 }
04354 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04355 if (option_debug > 0) {
04356 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04357 }
04358 return;
04359 }
04360
04361 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04362 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04363 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04364 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04365 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04366 }
04367
04368 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04369 struct timeval tv = { inttime, };
04370 struct ast_tm tm;
04371 ast_localtime(&tv, &tm, NULL);
04372 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04373 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04374 }
04375 ast_config_destroy(msg_cfg);
04376 }
04377
04378
04379
04380
04381
04382
04383
04384
04385
04386 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04387 {
04388 const char *ptr;
04389
04390
04391 ast_str_set(buf, maxlen, "\"");
04392 for (ptr = from; *ptr; ptr++) {
04393 if (*ptr == '"' || *ptr == '\\') {
04394 ast_str_append(buf, maxlen, "\\%c", *ptr);
04395 } else {
04396 ast_str_append(buf, maxlen, "%c", *ptr);
04397 }
04398 }
04399 ast_str_append(buf, maxlen, "\"");
04400
04401 return ast_str_buffer(*buf);
04402 }
04403
04404
04405
04406
04407
04408 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04409 {
04410 const struct vm_zone *z = NULL;
04411 struct timeval t = ast_tvnow();
04412
04413
04414 if (!ast_strlen_zero(vmu->zonetag)) {
04415
04416 AST_LIST_LOCK(&zones);
04417 AST_LIST_TRAVERSE(&zones, z, list) {
04418 if (!strcmp(z->name, vmu->zonetag))
04419 break;
04420 }
04421 AST_LIST_UNLOCK(&zones);
04422 }
04423 ast_localtime(&t, tm, z ? z->timezone : NULL);
04424 return tm;
04425 }
04426
04427
04428
04429
04430
04431 static int check_mime(const char *str)
04432 {
04433 for (; *str; str++) {
04434 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04435 return 1;
04436 }
04437 }
04438 return 0;
04439 }
04440
04441
04442
04443
04444
04445
04446
04447
04448
04449
04450
04451
04452
04453
04454
04455
04456
04457
04458 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04459 {
04460 struct ast_str *tmp = ast_str_alloca(80);
04461 int first_section = 1;
04462
04463 ast_str_reset(*end);
04464 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04465 for (; *start; start++) {
04466 int need_encoding = 0;
04467 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04468 need_encoding = 1;
04469 }
04470 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04471 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04472 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04473 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04474
04475 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04476 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04477 first_section = 0;
04478 }
04479 if (need_encoding && *start == ' ') {
04480 ast_str_append(&tmp, -1, "_");
04481 } else if (need_encoding) {
04482 ast_str_append(&tmp, -1, "=%hhX", *start);
04483 } else {
04484 ast_str_append(&tmp, -1, "%c", *start);
04485 }
04486 }
04487 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04488 return ast_str_buffer(*end);
04489 }
04490
04491
04492
04493
04494
04495
04496
04497
04498
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514 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)
04515 {
04516 char date[256];
04517 char host[MAXHOSTNAMELEN] = "";
04518 char who[256];
04519 char bound[256];
04520 char dur[256];
04521 struct ast_tm tm;
04522 char enc_cidnum[256] = "", enc_cidname[256] = "";
04523 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04524 char *greeting_attachment;
04525 char filename[256];
04526
04527 if (!str1 || !str2) {
04528 ast_free(str1);
04529 ast_free(str2);
04530 return;
04531 }
04532
04533 if (cidnum) {
04534 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04535 }
04536 if (cidname) {
04537 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04538 }
04539 gethostname(host, sizeof(host) - 1);
04540
04541 if (strchr(srcemail, '@')) {
04542 ast_copy_string(who, srcemail, sizeof(who));
04543 } else {
04544 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04545 }
04546
04547 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04548 if (greeting_attachment) {
04549 *greeting_attachment++ = '\0';
04550 }
04551
04552 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04553 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04554 fprintf(p, "Date: %s" ENDL, date);
04555
04556
04557 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04558
04559 if (!ast_strlen_zero(fromstring)) {
04560 struct ast_channel *ast;
04561 if ((ast = ast_dummy_channel_alloc())) {
04562 char *ptr;
04563 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04564 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04565
04566 if (check_mime(ast_str_buffer(str1))) {
04567 int first_line = 1;
04568 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04569 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04570 *ptr = '\0';
04571 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04572 first_line = 0;
04573
04574 ast_str_set(&str2, 0, "%s", ptr + 1);
04575 }
04576 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04577 } else {
04578 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04579 }
04580 ast = ast_channel_unref(ast);
04581 } else {
04582 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04583 }
04584 } else {
04585 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04586 }
04587
04588 if (check_mime(vmu->fullname)) {
04589 int first_line = 1;
04590 char *ptr;
04591 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04592 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04593 *ptr = '\0';
04594 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04595 first_line = 0;
04596
04597 ast_str_set(&str2, 0, "%s", ptr + 1);
04598 }
04599 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04600 } else {
04601 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04602 }
04603
04604 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04605 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04606 struct ast_channel *ast;
04607 if ((ast = ast_dummy_channel_alloc())) {
04608 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04609 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04610 if (check_mime(ast_str_buffer(str1))) {
04611 int first_line = 1;
04612 char *ptr;
04613 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04614 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04615 *ptr = '\0';
04616 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04617 first_line = 0;
04618
04619 ast_str_set(&str2, 0, "%s", ptr + 1);
04620 }
04621 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04622 } else {
04623 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04624 }
04625 ast = ast_channel_unref(ast);
04626 } else {
04627 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04628 }
04629 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04630 if (ast_strlen_zero(flag)) {
04631 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04632 } else {
04633 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04634 }
04635 } else {
04636 if (ast_strlen_zero(flag)) {
04637 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04638 } else {
04639 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04640 }
04641 }
04642
04643 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04644 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04645 if (imap) {
04646
04647 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04648
04649 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04650 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04651 #ifdef IMAP_STORAGE
04652 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04653 #else
04654 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04655 #endif
04656
04657 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04658 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04659 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04660 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04661 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04662 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04663 if (!ast_strlen_zero(category)) {
04664 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04665 } else {
04666 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04667 }
04668 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04669 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04670 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04671 }
04672 if (!ast_strlen_zero(cidnum)) {
04673 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04674 }
04675 if (!ast_strlen_zero(cidname)) {
04676 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04677 }
04678 fprintf(p, "MIME-Version: 1.0" ENDL);
04679 if (attach_user_voicemail) {
04680
04681 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04682 (int) getpid(), (unsigned int) ast_random());
04683
04684 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04685 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04686 fprintf(p, "--%s" ENDL, bound);
04687 }
04688 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04689 if (emailbody || vmu->emailbody) {
04690 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04691 struct ast_channel *ast;
04692 if ((ast = ast_dummy_channel_alloc())) {
04693 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04694 ast_str_substitute_variables(&str1, 0, ast, e_body);
04695 #ifdef IMAP_STORAGE
04696 {
04697
04698 char *line = ast_str_buffer(str1), *next;
04699 do {
04700
04701 if ((next = strchr(line, '\n'))) {
04702 *next++ = '\0';
04703 }
04704 fprintf(p, "%s" ENDL, line);
04705 line = next;
04706 } while (!ast_strlen_zero(line));
04707 }
04708 #else
04709 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04710 #endif
04711 ast = ast_channel_unref(ast);
04712 } else {
04713 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04714 }
04715 } else if (msgnum > -1) {
04716 if (strcmp(vmu->mailbox, mailbox)) {
04717
04718 struct ast_config *msg_cfg;
04719 const char *v;
04720 int inttime;
04721 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04722 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04723
04724 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04725 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04726 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04727 strcat(fromfile, ".txt");
04728 }
04729 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04730 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04731 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04732 }
04733
04734
04735
04736 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04737 struct timeval tv = { inttime, };
04738 struct ast_tm tm;
04739 ast_localtime(&tv, &tm, NULL);
04740 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04741 }
04742 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04743 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04744 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04745 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04746 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04747 date, origcallerid, origdate);
04748 ast_config_destroy(msg_cfg);
04749 } else {
04750 goto plain_message;
04751 }
04752 } else {
04753 plain_message:
04754 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04755 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04756 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04757 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04758 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04759 }
04760 } else {
04761 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04762 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04763 }
04764
04765 if (imap || attach_user_voicemail) {
04766 if (!ast_strlen_zero(attach2)) {
04767 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04768 ast_debug(5, "creating second attachment filename %s\n", filename);
04769 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04770 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04771 ast_debug(5, "creating attachment filename %s\n", filename);
04772 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04773 } else {
04774 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04775 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04776 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04777 }
04778 }
04779 ast_free(str1);
04780 ast_free(str2);
04781 }
04782
04783 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)
04784 {
04785 char tmpdir[256], newtmp[256];
04786 char fname[256];
04787 char tmpcmd[256];
04788 int tmpfd = -1;
04789 int soxstatus = 0;
04790
04791
04792 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04793
04794 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04795 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04796 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04797 tmpfd = mkstemp(newtmp);
04798 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04799 ast_debug(3, "newtmp: %s\n", newtmp);
04800 if (tmpfd > -1) {
04801 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04802 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04803 attach = newtmp;
04804 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04805 } else {
04806 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04807 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04808 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04809 }
04810 }
04811 }
04812 fprintf(p, "--%s" ENDL, bound);
04813 if (msgnum > -1)
04814 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04815 else
04816 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04817 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04818 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04819 if (msgnum > -1)
04820 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04821 else
04822 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04823 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04824 base_encode(fname, p);
04825 if (last)
04826 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04827 if (tmpfd > -1) {
04828 if (soxstatus == 0) {
04829 unlink(fname);
04830 }
04831 close(tmpfd);
04832 unlink(newtmp);
04833 }
04834 return 0;
04835 }
04836
04837 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)
04838 {
04839 FILE *p = NULL;
04840 char tmp[80] = "/tmp/astmail-XXXXXX";
04841 char tmp2[256];
04842 char *stringp;
04843
04844 if (vmu && ast_strlen_zero(vmu->email)) {
04845 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04846 return(0);
04847 }
04848
04849
04850 format = ast_strdupa(format);
04851 stringp = format;
04852 strsep(&stringp, "|");
04853
04854 if (!strcmp(format, "wav49"))
04855 format = "WAV";
04856 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04857
04858
04859 if ((p = vm_mkftemp(tmp)) == NULL) {
04860 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04861 return -1;
04862 } else {
04863 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04864 fclose(p);
04865 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04866 ast_safe_system(tmp2);
04867 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04868 }
04869 return 0;
04870 }
04871
04872 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)
04873 {
04874 char enc_cidnum[256], enc_cidname[256];
04875 char date[256];
04876 char host[MAXHOSTNAMELEN] = "";
04877 char who[256];
04878 char dur[PATH_MAX];
04879 char tmp[80] = "/tmp/astmail-XXXXXX";
04880 char tmp2[PATH_MAX];
04881 struct ast_tm tm;
04882 FILE *p;
04883 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04884
04885 if (!str1 || !str2) {
04886 ast_free(str1);
04887 ast_free(str2);
04888 return -1;
04889 }
04890
04891 if (cidnum) {
04892 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04893 }
04894 if (cidname) {
04895 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04896 }
04897
04898 if ((p = vm_mkftemp(tmp)) == NULL) {
04899 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04900 ast_free(str1);
04901 ast_free(str2);
04902 return -1;
04903 }
04904 gethostname(host, sizeof(host)-1);
04905 if (strchr(srcemail, '@')) {
04906 ast_copy_string(who, srcemail, sizeof(who));
04907 } else {
04908 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04909 }
04910 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04911 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04912 fprintf(p, "Date: %s\n", date);
04913
04914
04915 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04916
04917 if (!ast_strlen_zero(pagerfromstring)) {
04918 struct ast_channel *ast;
04919 if ((ast = ast_dummy_channel_alloc())) {
04920 char *ptr;
04921 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04922 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04923
04924 if (check_mime(ast_str_buffer(str1))) {
04925 int first_line = 1;
04926 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04927 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04928 *ptr = '\0';
04929 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04930 first_line = 0;
04931
04932 ast_str_set(&str2, 0, "%s", ptr + 1);
04933 }
04934 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04935 } else {
04936 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04937 }
04938 ast = ast_channel_unref(ast);
04939 } else {
04940 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04941 }
04942 } else {
04943 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04944 }
04945
04946 if (check_mime(vmu->fullname)) {
04947 int first_line = 1;
04948 char *ptr;
04949 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04950 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04951 *ptr = '\0';
04952 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04953 first_line = 0;
04954
04955 ast_str_set(&str2, 0, "%s", ptr + 1);
04956 }
04957 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04958 } else {
04959 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04960 }
04961
04962 if (!ast_strlen_zero(pagersubject)) {
04963 struct ast_channel *ast;
04964 if ((ast = ast_dummy_channel_alloc())) {
04965 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04966 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04967 if (check_mime(ast_str_buffer(str1))) {
04968 int first_line = 1;
04969 char *ptr;
04970 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04971 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04972 *ptr = '\0';
04973 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04974 first_line = 0;
04975
04976 ast_str_set(&str2, 0, "%s", ptr + 1);
04977 }
04978 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04979 } else {
04980 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04981 }
04982 ast = ast_channel_unref(ast);
04983 } else {
04984 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04985 }
04986 } else {
04987 if (ast_strlen_zero(flag)) {
04988 fprintf(p, "Subject: New VM\n\n");
04989 } else {
04990 fprintf(p, "Subject: New %s VM\n\n", flag);
04991 }
04992 }
04993
04994 if (pagerbody) {
04995 struct ast_channel *ast;
04996 if ((ast = ast_dummy_channel_alloc())) {
04997 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04998 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
04999 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05000 ast = ast_channel_unref(ast);
05001 } else {
05002 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05003 }
05004 } else {
05005 fprintf(p, "New %s long %s msg in box %s\n"
05006 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05007 }
05008
05009 fclose(p);
05010 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05011 ast_safe_system(tmp2);
05012 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05013 ast_free(str1);
05014 ast_free(str2);
05015 return 0;
05016 }
05017
05018
05019
05020
05021
05022
05023
05024
05025
05026
05027 static int get_date(char *s, int len)
05028 {
05029 struct ast_tm tm;
05030 struct timeval t = ast_tvnow();
05031
05032 ast_localtime(&t, &tm, "UTC");
05033
05034 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05035 }
05036
05037 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05038 {
05039 int res;
05040 char fn[PATH_MAX];
05041 char dest[PATH_MAX];
05042
05043 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05044
05045 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05046 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05047 return -1;
05048 }
05049
05050 RETRIEVE(fn, -1, ext, context);
05051 if (ast_fileexists(fn, NULL, NULL) > 0) {
05052 res = ast_stream_and_wait(chan, fn, ecodes);
05053 if (res) {
05054 DISPOSE(fn, -1);
05055 return res;
05056 }
05057 } else {
05058
05059 DISPOSE(fn, -1);
05060 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05061 if (res)
05062 return res;
05063 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05064 if (res)
05065 return res;
05066 }
05067 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05068 return res;
05069 }
05070
05071 static void free_zone(struct vm_zone *z)
05072 {
05073 ast_free(z);
05074 }
05075
05076 #ifdef ODBC_STORAGE
05077 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05078 {
05079 int x = -1;
05080 int res;
05081 SQLHSTMT stmt = NULL;
05082 char sql[PATH_MAX];
05083 char rowdata[20];
05084 char tmp[PATH_MAX] = "";
05085 struct odbc_obj *obj = NULL;
05086 char *context;
05087 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05088
05089 if (newmsgs)
05090 *newmsgs = 0;
05091 if (oldmsgs)
05092 *oldmsgs = 0;
05093 if (urgentmsgs)
05094 *urgentmsgs = 0;
05095
05096
05097 if (ast_strlen_zero(mailbox))
05098 return 0;
05099
05100 ast_copy_string(tmp, mailbox, sizeof(tmp));
05101
05102 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05103 int u, n, o;
05104 char *next, *remaining = tmp;
05105 while ((next = strsep(&remaining, " ,"))) {
05106 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05107 return -1;
05108 }
05109 if (urgentmsgs) {
05110 *urgentmsgs += u;
05111 }
05112 if (newmsgs) {
05113 *newmsgs += n;
05114 }
05115 if (oldmsgs) {
05116 *oldmsgs += o;
05117 }
05118 }
05119 return 0;
05120 }
05121
05122 context = strchr(tmp, '@');
05123 if (context) {
05124 *context = '\0';
05125 context++;
05126 } else
05127 context = "default";
05128
05129 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05130 do {
05131 if (newmsgs) {
05132 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05133 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05134 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05135 break;
05136 }
05137 res = SQLFetch(stmt);
05138 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05139 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05140 break;
05141 }
05142 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05143 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05144 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05145 break;
05146 }
05147 *newmsgs = atoi(rowdata);
05148 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05149 }
05150
05151 if (oldmsgs) {
05152 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05153 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05154 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05155 break;
05156 }
05157 res = SQLFetch(stmt);
05158 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05159 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05160 break;
05161 }
05162 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05163 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05164 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05165 break;
05166 }
05167 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05168 *oldmsgs = atoi(rowdata);
05169 }
05170
05171 if (urgentmsgs) {
05172 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05173 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05174 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05175 break;
05176 }
05177 res = SQLFetch(stmt);
05178 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05179 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05180 break;
05181 }
05182 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05183 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05184 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05185 break;
05186 }
05187 *urgentmsgs = atoi(rowdata);
05188 }
05189
05190 x = 0;
05191 } while (0);
05192 } else {
05193 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05194 }
05195
05196 if (stmt) {
05197 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05198 }
05199 if (obj) {
05200 ast_odbc_release_obj(obj);
05201 }
05202 return x;
05203 }
05204
05205
05206
05207
05208
05209
05210
05211
05212
05213
05214 static int messagecount(const char *context, const char *mailbox, const char *folder)
05215 {
05216 struct odbc_obj *obj = NULL;
05217 int nummsgs = 0;
05218 int res;
05219 SQLHSTMT stmt = NULL;
05220 char sql[PATH_MAX];
05221 char rowdata[20];
05222 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05223 if (!folder)
05224 folder = "INBOX";
05225
05226 if (ast_strlen_zero(mailbox))
05227 return 0;
05228
05229 obj = ast_odbc_request_obj(odbc_database, 0);
05230 if (obj) {
05231 if (!strcmp(folder, "INBOX")) {
05232 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);
05233 } else {
05234 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05235 }
05236 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05237 if (!stmt) {
05238 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05239 goto yuck;
05240 }
05241 res = SQLFetch(stmt);
05242 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05243 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05244 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05245 goto yuck;
05246 }
05247 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05248 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05249 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05250 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05251 goto yuck;
05252 }
05253 nummsgs = atoi(rowdata);
05254 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05255 } else
05256 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05257
05258 yuck:
05259 if (obj)
05260 ast_odbc_release_obj(obj);
05261 return nummsgs;
05262 }
05263
05264
05265
05266
05267
05268
05269
05270
05271
05272 static int has_voicemail(const char *mailbox, const char *folder)
05273 {
05274 char tmp[256], *tmp2 = tmp, *box, *context;
05275 ast_copy_string(tmp, mailbox, sizeof(tmp));
05276 while ((context = box = strsep(&tmp2, ",&"))) {
05277 strsep(&context, "@");
05278 if (ast_strlen_zero(context))
05279 context = "default";
05280 if (messagecount(context, box, folder))
05281 return 1;
05282 }
05283 return 0;
05284 }
05285 #endif
05286 #ifndef IMAP_STORAGE
05287
05288
05289
05290
05291
05292
05293
05294
05295
05296
05297
05298
05299
05300
05301
05302
05303 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)
05304 {
05305 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05306 const char *frombox = mbox(vmu, imbox);
05307 const char *userfolder;
05308 int recipmsgnum;
05309 int res = 0;
05310
05311 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05312
05313 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05314 userfolder = "Urgent";
05315 } else {
05316 userfolder = "INBOX";
05317 }
05318
05319 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05320
05321 if (!dir)
05322 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05323 else
05324 ast_copy_string(fromdir, dir, sizeof(fromdir));
05325
05326 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05327 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05328
05329 if (vm_lock_path(todir))
05330 return ERROR_LOCK_PATH;
05331
05332 recipmsgnum = last_message_index(recip, todir) + 1;
05333 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05334 make_file(topath, sizeof(topath), todir, recipmsgnum);
05335 #ifndef ODBC_STORAGE
05336 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05337 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05338 } else {
05339 #endif
05340
05341
05342
05343 copy_plain_file(frompath, topath);
05344 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05345 vm_delete(topath);
05346 #ifndef ODBC_STORAGE
05347 }
05348 #endif
05349 } else {
05350 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05351 res = -1;
05352 }
05353 ast_unlock_path(todir);
05354 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05355 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05356 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05357 flag);
05358
05359 return res;
05360 }
05361 #endif
05362 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05363
05364 static int messagecount(const char *context, const char *mailbox, const char *folder)
05365 {
05366 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05367 }
05368
05369 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05370 {
05371 DIR *dir;
05372 struct dirent *de;
05373 char fn[256];
05374 int ret = 0;
05375
05376
05377 if (ast_strlen_zero(mailbox))
05378 return 0;
05379
05380 if (ast_strlen_zero(folder))
05381 folder = "INBOX";
05382 if (ast_strlen_zero(context))
05383 context = "default";
05384
05385 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05386
05387 if (!(dir = opendir(fn)))
05388 return 0;
05389
05390 while ((de = readdir(dir))) {
05391 if (!strncasecmp(de->d_name, "msg", 3)) {
05392 if (shortcircuit) {
05393 ret = 1;
05394 break;
05395 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05396 ret++;
05397 }
05398 }
05399 }
05400
05401 closedir(dir);
05402
05403 return ret;
05404 }
05405
05406
05407
05408
05409
05410
05411
05412
05413
05414
05415 static int has_voicemail(const char *mailbox, const char *folder)
05416 {
05417 char tmp[256], *tmp2 = tmp, *box, *context;
05418 ast_copy_string(tmp, mailbox, sizeof(tmp));
05419 if (ast_strlen_zero(folder)) {
05420 folder = "INBOX";
05421 }
05422 while ((box = strsep(&tmp2, ",&"))) {
05423 if ((context = strchr(box, '@')))
05424 *context++ = '\0';
05425 else
05426 context = "default";
05427 if (__has_voicemail(context, box, folder, 1))
05428 return 1;
05429
05430 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05431 return 1;
05432 }
05433 }
05434 return 0;
05435 }
05436
05437
05438 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05439 {
05440 char tmp[256];
05441 char *context;
05442
05443
05444 if (ast_strlen_zero(mailbox))
05445 return 0;
05446
05447 if (newmsgs)
05448 *newmsgs = 0;
05449 if (oldmsgs)
05450 *oldmsgs = 0;
05451 if (urgentmsgs)
05452 *urgentmsgs = 0;
05453
05454 if (strchr(mailbox, ',')) {
05455 int tmpnew, tmpold, tmpurgent;
05456 char *mb, *cur;
05457
05458 ast_copy_string(tmp, mailbox, sizeof(tmp));
05459 mb = tmp;
05460 while ((cur = strsep(&mb, ", "))) {
05461 if (!ast_strlen_zero(cur)) {
05462 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05463 return -1;
05464 else {
05465 if (newmsgs)
05466 *newmsgs += tmpnew;
05467 if (oldmsgs)
05468 *oldmsgs += tmpold;
05469 if (urgentmsgs)
05470 *urgentmsgs += tmpurgent;
05471 }
05472 }
05473 }
05474 return 0;
05475 }
05476
05477 ast_copy_string(tmp, mailbox, sizeof(tmp));
05478
05479 if ((context = strchr(tmp, '@')))
05480 *context++ = '\0';
05481 else
05482 context = "default";
05483
05484 if (newmsgs)
05485 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05486 if (oldmsgs)
05487 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05488 if (urgentmsgs)
05489 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05490
05491 return 0;
05492 }
05493
05494 #endif
05495
05496
05497 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05498 {
05499 int urgentmsgs = 0;
05500 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05501 if (newmsgs) {
05502 *newmsgs += urgentmsgs;
05503 }
05504 return res;
05505 }
05506
05507 static void run_externnotify(char *context, char *extension, const char *flag)
05508 {
05509 char arguments[255];
05510 char ext_context[256] = "";
05511 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05512 struct ast_smdi_mwi_message *mwi_msg;
05513
05514 if (!ast_strlen_zero(context))
05515 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05516 else
05517 ast_copy_string(ext_context, extension, sizeof(ext_context));
05518
05519 if (smdi_iface) {
05520 if (ast_app_has_voicemail(ext_context, NULL))
05521 ast_smdi_mwi_set(smdi_iface, extension);
05522 else
05523 ast_smdi_mwi_unset(smdi_iface, extension);
05524
05525 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05526 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05527 if (!strncmp(mwi_msg->cause, "INV", 3))
05528 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05529 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05530 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05531 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05532 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05533 } else {
05534 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05535 }
05536 }
05537
05538 if (!ast_strlen_zero(externnotify)) {
05539 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05540 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05541 } else {
05542 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05543 ast_debug(1, "Executing %s\n", arguments);
05544 ast_safe_system(arguments);
05545 }
05546 }
05547 }
05548
05549
05550
05551
05552
05553
05554 struct leave_vm_options {
05555 unsigned int flags;
05556 signed char record_gain;
05557 char *exitcontext;
05558 };
05559
05560
05561
05562
05563
05564
05565
05566
05567
05568
05569
05570 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05571 {
05572 #ifdef IMAP_STORAGE
05573 int newmsgs, oldmsgs;
05574 #else
05575 char urgdir[PATH_MAX];
05576 #endif
05577 char txtfile[PATH_MAX];
05578 char tmptxtfile[PATH_MAX];
05579 struct vm_state *vms = NULL;
05580 char callerid[256];
05581 FILE *txt;
05582 char date[256];
05583 int txtdes;
05584 int res = 0;
05585 int msgnum;
05586 int duration = 0;
05587 int sound_duration = 0;
05588 int ausemacro = 0;
05589 int ousemacro = 0;
05590 int ouseexten = 0;
05591 char tmpdur[16];
05592 char priority[16];
05593 char origtime[16];
05594 char dir[PATH_MAX];
05595 char tmpdir[PATH_MAX];
05596 char fn[PATH_MAX];
05597 char prefile[PATH_MAX] = "";
05598 char tempfile[PATH_MAX] = "";
05599 char ext_context[256] = "";
05600 char fmt[80];
05601 char *context;
05602 char ecodes[17] = "#";
05603 struct ast_str *tmp = ast_str_create(16);
05604 char *tmpptr;
05605 struct ast_vm_user *vmu;
05606 struct ast_vm_user svm;
05607 const char *category = NULL;
05608 const char *code;
05609 const char *alldtmf = "0123456789ABCD*#";
05610 char flag[80];
05611
05612 if (!tmp) {
05613 return -1;
05614 }
05615
05616 ast_str_set(&tmp, 0, "%s", ext);
05617 ext = ast_str_buffer(tmp);
05618 if ((context = strchr(ext, '@'))) {
05619 *context++ = '\0';
05620 tmpptr = strchr(context, '&');
05621 } else {
05622 tmpptr = strchr(ext, '&');
05623 }
05624
05625 if (tmpptr)
05626 *tmpptr++ = '\0';
05627
05628 ast_channel_lock(chan);
05629 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05630 category = ast_strdupa(category);
05631 }
05632 ast_channel_unlock(chan);
05633
05634 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05635 ast_copy_string(flag, "Urgent", sizeof(flag));
05636 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05637 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05638 } else {
05639 flag[0] = '\0';
05640 }
05641
05642 ast_debug(3, "Before find_user\n");
05643 if (!(vmu = find_user(&svm, context, ext))) {
05644 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05645 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05646 ast_free(tmp);
05647 return res;
05648 }
05649
05650 if (strcmp(vmu->context, "default"))
05651 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05652 else
05653 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05654
05655
05656
05657
05658
05659
05660 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05661 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05662 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05663 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05664 }
05665
05666
05667
05668
05669 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05670 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05671 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05672 ast_free(tmp);
05673 return -1;
05674 }
05675 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05676 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05677 ast_copy_string(prefile, tempfile, sizeof(prefile));
05678
05679 DISPOSE(tempfile, -1);
05680
05681 #ifndef IMAP_STORAGE
05682 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05683 #else
05684 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05685 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05686 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05687 }
05688 #endif
05689
05690
05691 if (ast_test_flag(vmu, VM_OPERATOR)) {
05692 if (!ast_strlen_zero(vmu->exit)) {
05693 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05694 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05695 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05696 ouseexten = 1;
05697 }
05698 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05699 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05700 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05701 ouseexten = 1;
05702 } else if (!ast_strlen_zero(chan->macrocontext)
05703 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05704 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05705 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05706 ousemacro = 1;
05707 }
05708 }
05709
05710 if (!ast_strlen_zero(vmu->exit)) {
05711 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05712 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05713 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05714 }
05715 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05716 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05717 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05718 } else if (!ast_strlen_zero(chan->macrocontext)
05719 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05720 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05721 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05722 ausemacro = 1;
05723 }
05724
05725 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05726 for (code = alldtmf; *code; code++) {
05727 char e[2] = "";
05728 e[0] = *code;
05729 if (strchr(ecodes, e[0]) == NULL
05730 && ast_canmatch_extension(chan,
05731 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05732 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05733 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05734 }
05735 }
05736 }
05737
05738
05739 if (!ast_strlen_zero(prefile)) {
05740 #ifdef ODBC_STORAGE
05741 int success =
05742 #endif
05743 RETRIEVE(prefile, -1, ext, context);
05744 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05745 if (ast_streamfile(chan, prefile, chan->language) > -1)
05746 res = ast_waitstream(chan, ecodes);
05747 #ifdef ODBC_STORAGE
05748 if (success == -1) {
05749
05750 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05751 store_file(prefile, vmu->mailbox, vmu->context, -1);
05752 }
05753 #endif
05754 } else {
05755 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05756 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05757 }
05758 DISPOSE(prefile, -1);
05759 if (res < 0) {
05760 ast_debug(1, "Hang up during prefile playback\n");
05761 free_user(vmu);
05762 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05763 ast_free(tmp);
05764 return -1;
05765 }
05766 }
05767 if (res == '#') {
05768
05769 ast_set_flag(options, OPT_SILENT);
05770 res = 0;
05771 }
05772
05773 if (vmu->maxmsg == 0) {
05774 if (option_debug > 2)
05775 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05776 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05777 goto leave_vm_out;
05778 }
05779 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05780 res = ast_stream_and_wait(chan, INTRO, ecodes);
05781 if (res == '#') {
05782 ast_set_flag(options, OPT_SILENT);
05783 res = 0;
05784 }
05785 }
05786 if (res > 0)
05787 ast_stopstream(chan);
05788
05789
05790 if (res == '*') {
05791 chan->exten[0] = 'a';
05792 chan->exten[1] = '\0';
05793 if (!ast_strlen_zero(vmu->exit)) {
05794 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05795 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05796 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05797 }
05798 chan->priority = 0;
05799 free_user(vmu);
05800 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05801 ast_free(tmp);
05802 return 0;
05803 }
05804
05805
05806 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05807 transfer:
05808 if (ouseexten || ousemacro) {
05809 chan->exten[0] = 'o';
05810 chan->exten[1] = '\0';
05811 if (!ast_strlen_zero(vmu->exit)) {
05812 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05813 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05814 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05815 }
05816 ast_play_and_wait(chan, "transfer");
05817 chan->priority = 0;
05818 free_user(vmu);
05819 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05820 }
05821 ast_free(tmp);
05822 return OPERATOR_EXIT;
05823 }
05824
05825
05826 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05827 if (!ast_strlen_zero(options->exitcontext)) {
05828 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05829 }
05830 free_user(vmu);
05831 ast_free(tmp);
05832 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05833 return res;
05834 }
05835
05836 if (res < 0) {
05837 free_user(vmu);
05838 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05839 ast_free(tmp);
05840 return -1;
05841 }
05842
05843 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05844 if (!ast_strlen_zero(fmt)) {
05845 msgnum = 0;
05846
05847 #ifdef IMAP_STORAGE
05848
05849
05850 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05851 if (res < 0) {
05852 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05853 ast_free(tmp);
05854 return -1;
05855 }
05856 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05857
05858
05859
05860
05861 if (!(vms = create_vm_state_from_user(vmu))) {
05862 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05863 ast_free(tmp);
05864 return -1;
05865 }
05866 }
05867 vms->newmessages++;
05868
05869
05870 msgnum = newmsgs + oldmsgs;
05871 ast_debug(3, "Messagecount set to %d\n", msgnum);
05872 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05873
05874 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05875
05876 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05877 goto leave_vm_out;
05878 }
05879 #else
05880 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05881 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05882 if (!res)
05883 res = ast_waitstream(chan, "");
05884 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05885 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05886 inprocess_count(vmu->mailbox, vmu->context, -1);
05887 goto leave_vm_out;
05888 }
05889
05890 #endif
05891 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05892 txtdes = mkstemp(tmptxtfile);
05893 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05894 if (txtdes < 0) {
05895 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05896 if (!res)
05897 res = ast_waitstream(chan, "");
05898 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05899 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05900 inprocess_count(vmu->mailbox, vmu->context, -1);
05901 goto leave_vm_out;
05902 }
05903
05904
05905 if (res >= 0) {
05906
05907 res = ast_stream_and_wait(chan, "beep", "");
05908 }
05909
05910
05911 if (ast_check_realtime("voicemail_data")) {
05912 snprintf(priority, sizeof(priority), "%d", chan->priority);
05913 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05914 get_date(date, sizeof(date));
05915 ast_callerid_merge(callerid, sizeof(callerid),
05916 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05917 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05918 "Unknown");
05919 ast_store_realtime("voicemail_data",
05920 "origmailbox", ext,
05921 "context", chan->context,
05922 "macrocontext", chan->macrocontext,
05923 "exten", chan->exten,
05924 "priority", priority,
05925 "callerchan", chan->name,
05926 "callerid", callerid,
05927 "origdate", date,
05928 "origtime", origtime,
05929 "category", S_OR(category, ""),
05930 "filename", tmptxtfile,
05931 SENTINEL);
05932 }
05933
05934
05935 txt = fdopen(txtdes, "w+");
05936 if (txt) {
05937 get_date(date, sizeof(date));
05938 ast_callerid_merge(callerid, sizeof(callerid),
05939 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05940 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05941 "Unknown");
05942 fprintf(txt,
05943 ";\n"
05944 "; Message Information file\n"
05945 ";\n"
05946 "[message]\n"
05947 "origmailbox=%s\n"
05948 "context=%s\n"
05949 "macrocontext=%s\n"
05950 "exten=%s\n"
05951 "rdnis=%s\n"
05952 "priority=%d\n"
05953 "callerchan=%s\n"
05954 "callerid=%s\n"
05955 "origdate=%s\n"
05956 "origtime=%ld\n"
05957 "category=%s\n",
05958 ext,
05959 chan->context,
05960 chan->macrocontext,
05961 chan->exten,
05962 S_COR(chan->redirecting.from.number.valid,
05963 chan->redirecting.from.number.str, "unknown"),
05964 chan->priority,
05965 chan->name,
05966 callerid,
05967 date, (long) time(NULL),
05968 category ? category : "");
05969 } else {
05970 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05971 inprocess_count(vmu->mailbox, vmu->context, -1);
05972 if (ast_check_realtime("voicemail_data")) {
05973 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05974 }
05975 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05976 goto leave_vm_out;
05977 }
05978 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
05979
05980 if (txt) {
05981 fprintf(txt, "flag=%s\n", flag);
05982 if (sound_duration < vmu->minsecs) {
05983 fclose(txt);
05984 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
05985 ast_filedelete(tmptxtfile, NULL);
05986 unlink(tmptxtfile);
05987 if (ast_check_realtime("voicemail_data")) {
05988 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05989 }
05990 inprocess_count(vmu->mailbox, vmu->context, -1);
05991 } else {
05992 fprintf(txt, "duration=%d\n", duration);
05993 fclose(txt);
05994 if (vm_lock_path(dir)) {
05995 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05996
05997 ast_filedelete(tmptxtfile, NULL);
05998 unlink(tmptxtfile);
05999 inprocess_count(vmu->mailbox, vmu->context, -1);
06000 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06001 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06002 unlink(tmptxtfile);
06003 ast_unlock_path(dir);
06004 inprocess_count(vmu->mailbox, vmu->context, -1);
06005 if (ast_check_realtime("voicemail_data")) {
06006 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06007 }
06008 } else {
06009 #ifndef IMAP_STORAGE
06010 msgnum = last_message_index(vmu, dir) + 1;
06011 #endif
06012 make_file(fn, sizeof(fn), dir, msgnum);
06013
06014
06015 #ifndef IMAP_STORAGE
06016 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06017 #else
06018 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06019 #endif
06020
06021 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06022 ast_filerename(tmptxtfile, fn, NULL);
06023 rename(tmptxtfile, txtfile);
06024 inprocess_count(vmu->mailbox, vmu->context, -1);
06025
06026
06027
06028 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06029 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06030
06031 ast_unlock_path(dir);
06032 if (ast_check_realtime("voicemail_data")) {
06033 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06034 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06035 }
06036
06037
06038
06039 if (ast_fileexists(fn, NULL, NULL) > 0) {
06040 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06041 }
06042
06043
06044 while (tmpptr) {
06045 struct ast_vm_user recipu, *recip;
06046 char *exten, *cntx;
06047
06048 exten = strsep(&tmpptr, "&");
06049 cntx = strchr(exten, '@');
06050 if (cntx) {
06051 *cntx = '\0';
06052 cntx++;
06053 }
06054 if ((recip = find_user(&recipu, cntx, exten))) {
06055 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06056 free_user(recip);
06057 }
06058 }
06059 #ifndef IMAP_STORAGE
06060 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06061
06062 char sfn[PATH_MAX];
06063 char dfn[PATH_MAX];
06064 int x;
06065
06066 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06067 x = last_message_index(vmu, urgdir) + 1;
06068 make_file(sfn, sizeof(sfn), dir, msgnum);
06069 make_file(dfn, sizeof(dfn), urgdir, x);
06070 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06071 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06072
06073 ast_copy_string(fn, dfn, sizeof(fn));
06074 msgnum = x;
06075 }
06076 #endif
06077
06078 if (ast_fileexists(fn, NULL, NULL)) {
06079 #ifdef IMAP_STORAGE
06080 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06081 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06082 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06083 flag);
06084 #else
06085 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06086 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06087 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06088 flag);
06089 #endif
06090 }
06091
06092
06093 if (ast_fileexists(fn, NULL, NULL)) {
06094 DISPOSE(dir, msgnum);
06095 }
06096 }
06097 }
06098 } else {
06099 inprocess_count(vmu->mailbox, vmu->context, -1);
06100 }
06101 if (res == '0') {
06102 goto transfer;
06103 } else if (res > 0 && res != 't')
06104 res = 0;
06105
06106 if (sound_duration < vmu->minsecs)
06107
06108 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06109 else
06110 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06111 } else
06112 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06113 leave_vm_out:
06114 free_user(vmu);
06115
06116 #ifdef IMAP_STORAGE
06117
06118 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06119 if (expungeonhangup == 1) {
06120 ast_mutex_lock(&vms->lock);
06121 #ifdef HAVE_IMAP_TK2006
06122 if (LEVELUIDPLUS (vms->mailstream)) {
06123 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06124 } else
06125 #endif
06126 mail_expunge(vms->mailstream);
06127 ast_mutex_unlock(&vms->lock);
06128 }
06129 #endif
06130
06131 ast_free(tmp);
06132 return res;
06133 }
06134
06135 #if !defined(IMAP_STORAGE)
06136 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06137 {
06138
06139
06140 int x, dest;
06141 char sfn[PATH_MAX];
06142 char dfn[PATH_MAX];
06143
06144 if (vm_lock_path(dir)) {
06145 return ERROR_LOCK_PATH;
06146 }
06147
06148 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06149 make_file(sfn, sizeof(sfn), dir, x);
06150 if (EXISTS(dir, x, sfn, NULL)) {
06151
06152 if (x != dest) {
06153 make_file(dfn, sizeof(dfn), dir, dest);
06154 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06155 }
06156
06157 dest++;
06158 }
06159 }
06160 ast_unlock_path(dir);
06161
06162 return dest;
06163 }
06164 #endif
06165
06166 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06167 {
06168 int d;
06169 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06170 return d;
06171 }
06172
06173 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06174 {
06175 #ifdef IMAP_STORAGE
06176
06177
06178 char sequence[10];
06179 char mailbox[256];
06180 int res;
06181
06182
06183 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06184
06185 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06186 ast_mutex_lock(&vms->lock);
06187
06188 if (box == OLD_FOLDER) {
06189 mail_setflag(vms->mailstream, sequence, "\\Seen");
06190 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06191 } else if (box == NEW_FOLDER) {
06192 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06193 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06194 }
06195 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06196 ast_mutex_unlock(&vms->lock);
06197 return 0;
06198 }
06199
06200 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06201 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06202 if (mail_create(vms->mailstream, mailbox) == NIL)
06203 ast_debug(5, "Folder exists.\n");
06204 else
06205 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06206 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06207 ast_mutex_unlock(&vms->lock);
06208 return res;
06209 #else
06210 char *dir = vms->curdir;
06211 char *username = vms->username;
06212 char *context = vmu->context;
06213 char sfn[PATH_MAX];
06214 char dfn[PATH_MAX];
06215 char ddir[PATH_MAX];
06216 const char *dbox = mbox(vmu, box);
06217 int x, i;
06218 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06219
06220 if (vm_lock_path(ddir))
06221 return ERROR_LOCK_PATH;
06222
06223 x = last_message_index(vmu, ddir) + 1;
06224
06225 if (box == 10 && x >= vmu->maxdeletedmsg) {
06226 x--;
06227 for (i = 1; i <= x; i++) {
06228
06229 make_file(sfn, sizeof(sfn), ddir, i);
06230 make_file(dfn, sizeof(dfn), ddir, i - 1);
06231 if (EXISTS(ddir, i, sfn, NULL)) {
06232 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06233 } else
06234 break;
06235 }
06236 } else {
06237 if (x >= vmu->maxmsg) {
06238 ast_unlock_path(ddir);
06239 return -1;
06240 }
06241 }
06242 make_file(sfn, sizeof(sfn), dir, msg);
06243 make_file(dfn, sizeof(dfn), ddir, x);
06244 if (strcmp(sfn, dfn)) {
06245 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06246 }
06247 ast_unlock_path(ddir);
06248 #endif
06249 return 0;
06250 }
06251
06252 static int adsi_logo(unsigned char *buf)
06253 {
06254 int bytes = 0;
06255 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06256 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06257 return bytes;
06258 }
06259
06260 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06261 {
06262 unsigned char buf[256];
06263 int bytes = 0;
06264 int x;
06265 char num[5];
06266
06267 *useadsi = 0;
06268 bytes += ast_adsi_data_mode(buf + bytes);
06269 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06270
06271 bytes = 0;
06272 bytes += adsi_logo(buf);
06273 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06274 #ifdef DISPLAY
06275 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06276 #endif
06277 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06278 bytes += ast_adsi_data_mode(buf + bytes);
06279 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06280
06281 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06282 bytes = 0;
06283 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06284 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06285 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06286 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06287 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06288 return 0;
06289 }
06290
06291 #ifdef DISPLAY
06292
06293 bytes = 0;
06294 bytes += ast_adsi_logo(buf);
06295 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06296 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06297 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06298 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06299 #endif
06300 bytes = 0;
06301 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06302 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06303 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06304 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06305 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06306 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06307 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06308
06309 #ifdef DISPLAY
06310
06311 bytes = 0;
06312 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06313 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06314
06315 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06316 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06317 #endif
06318
06319 bytes = 0;
06320
06321 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06322 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06323 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06324 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06325 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06326 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06327 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06328
06329 #ifdef DISPLAY
06330
06331 bytes = 0;
06332 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06333 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06334 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06335 #endif
06336
06337 bytes = 0;
06338 for (x = 0; x < 5; x++) {
06339 snprintf(num, sizeof(num), "%d", x);
06340 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06341 }
06342 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06343 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06344
06345 #ifdef DISPLAY
06346
06347 bytes = 0;
06348 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06349 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06350 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06351 #endif
06352
06353 if (ast_adsi_end_download(chan)) {
06354 bytes = 0;
06355 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06356 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06357 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06358 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06359 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06360 return 0;
06361 }
06362 bytes = 0;
06363 bytes += ast_adsi_download_disconnect(buf + bytes);
06364 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06365 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06366
06367 ast_debug(1, "Done downloading scripts...\n");
06368
06369 #ifdef DISPLAY
06370
06371 bytes = 0;
06372 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06373 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06374 #endif
06375 ast_debug(1, "Restarting session...\n");
06376
06377 bytes = 0;
06378
06379 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06380 *useadsi = 1;
06381 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06382 } else
06383 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06384
06385 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06386 return 0;
06387 }
06388
06389 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06390 {
06391 int x;
06392 if (!ast_adsi_available(chan))
06393 return;
06394 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06395 if (x < 0)
06396 return;
06397 if (!x) {
06398 if (adsi_load_vmail(chan, useadsi)) {
06399 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06400 return;
06401 }
06402 } else
06403 *useadsi = 1;
06404 }
06405
06406 static void adsi_login(struct ast_channel *chan)
06407 {
06408 unsigned char buf[256];
06409 int bytes = 0;
06410 unsigned char keys[8];
06411 int x;
06412 if (!ast_adsi_available(chan))
06413 return;
06414
06415 for (x = 0; x < 8; x++)
06416 keys[x] = 0;
06417
06418 keys[3] = ADSI_KEY_APPS + 3;
06419
06420 bytes += adsi_logo(buf + bytes);
06421 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06422 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06423 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06424 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06425 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06426 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06427 bytes += ast_adsi_set_keys(buf + bytes, keys);
06428 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06429 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06430 }
06431
06432 static void adsi_password(struct ast_channel *chan)
06433 {
06434 unsigned char buf[256];
06435 int bytes = 0;
06436 unsigned char keys[8];
06437 int x;
06438 if (!ast_adsi_available(chan))
06439 return;
06440
06441 for (x = 0; x < 8; x++)
06442 keys[x] = 0;
06443
06444 keys[3] = ADSI_KEY_APPS + 3;
06445
06446 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06447 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06448 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06449 bytes += ast_adsi_set_keys(buf + bytes, keys);
06450 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06451 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06452 }
06453
06454 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06455 {
06456 unsigned char buf[256];
06457 int bytes = 0;
06458 unsigned char keys[8];
06459 int x, y;
06460
06461 if (!ast_adsi_available(chan))
06462 return;
06463
06464 for (x = 0; x < 5; x++) {
06465 y = ADSI_KEY_APPS + 12 + start + x;
06466 if (y > ADSI_KEY_APPS + 12 + 4)
06467 y = 0;
06468 keys[x] = ADSI_KEY_SKT | y;
06469 }
06470 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06471 keys[6] = 0;
06472 keys[7] = 0;
06473
06474 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06475 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06476 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06477 bytes += ast_adsi_set_keys(buf + bytes, keys);
06478 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06479
06480 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06481 }
06482
06483 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06484 {
06485 int bytes = 0;
06486 unsigned char buf[256];
06487 char buf1[256], buf2[256];
06488 char fn2[PATH_MAX];
06489
06490 char cid[256] = "";
06491 char *val;
06492 char *name, *num;
06493 char datetime[21] = "";
06494 FILE *f;
06495
06496 unsigned char keys[8];
06497
06498 int x;
06499
06500 if (!ast_adsi_available(chan))
06501 return;
06502
06503
06504 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06505 f = fopen(fn2, "r");
06506 if (f) {
06507 while (!feof(f)) {
06508 if (!fgets((char *) buf, sizeof(buf), f)) {
06509 continue;
06510 }
06511 if (!feof(f)) {
06512 char *stringp = NULL;
06513 stringp = (char *) buf;
06514 strsep(&stringp, "=");
06515 val = strsep(&stringp, "=");
06516 if (!ast_strlen_zero(val)) {
06517 if (!strcmp((char *) buf, "callerid"))
06518 ast_copy_string(cid, val, sizeof(cid));
06519 if (!strcmp((char *) buf, "origdate"))
06520 ast_copy_string(datetime, val, sizeof(datetime));
06521 }
06522 }
06523 }
06524 fclose(f);
06525 }
06526
06527 for (x = 0; x < 5; x++)
06528 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06529 keys[6] = 0x0;
06530 keys[7] = 0x0;
06531
06532 if (!vms->curmsg) {
06533
06534 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06535 }
06536 if (vms->curmsg >= vms->lastmsg) {
06537
06538 if (vms->curmsg) {
06539
06540 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06541 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06542
06543 } else {
06544
06545 keys[3] = 1;
06546 }
06547 }
06548
06549 if (!ast_strlen_zero(cid)) {
06550 ast_callerid_parse(cid, &name, &num);
06551 if (!name)
06552 name = num;
06553 } else
06554 name = "Unknown Caller";
06555
06556
06557 #ifdef IMAP_STORAGE
06558 ast_mutex_lock(&vms->lock);
06559 #endif
06560 if (vms->deleted[vms->curmsg]) {
06561 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06562 }
06563 #ifdef IMAP_STORAGE
06564 ast_mutex_unlock(&vms->lock);
06565 #endif
06566
06567
06568 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06569 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06570 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06571 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06572
06573 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06574 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06575 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06576 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06577 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06578 bytes += ast_adsi_set_keys(buf + bytes, keys);
06579 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06580
06581 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06582 }
06583
06584 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06585 {
06586 int bytes = 0;
06587 unsigned char buf[256];
06588 unsigned char keys[8];
06589
06590 int x;
06591
06592 if (!ast_adsi_available(chan))
06593 return;
06594
06595
06596 for (x = 0; x < 5; x++)
06597 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06598
06599 keys[6] = 0x0;
06600 keys[7] = 0x0;
06601
06602 if (!vms->curmsg) {
06603
06604 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06605 }
06606 if (vms->curmsg >= vms->lastmsg) {
06607
06608 if (vms->curmsg) {
06609
06610 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06611 } else {
06612
06613 keys[3] = 1;
06614 }
06615 }
06616
06617
06618 #ifdef IMAP_STORAGE
06619 ast_mutex_lock(&vms->lock);
06620 #endif
06621 if (vms->deleted[vms->curmsg]) {
06622 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06623 }
06624 #ifdef IMAP_STORAGE
06625 ast_mutex_unlock(&vms->lock);
06626 #endif
06627
06628
06629 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06630 bytes += ast_adsi_set_keys(buf + bytes, keys);
06631 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06632
06633 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06634 }
06635
06636 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06637 {
06638 unsigned char buf[256] = "";
06639 char buf1[256] = "", buf2[256] = "";
06640 int bytes = 0;
06641 unsigned char keys[8];
06642 int x;
06643
06644 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06645 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06646 if (!ast_adsi_available(chan))
06647 return;
06648 if (vms->newmessages) {
06649 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06650 if (vms->oldmessages) {
06651 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06652 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06653 } else {
06654 snprintf(buf2, sizeof(buf2), "%s.", newm);
06655 }
06656 } else if (vms->oldmessages) {
06657 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06658 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06659 } else {
06660 strcpy(buf1, "You have no messages.");
06661 buf2[0] = ' ';
06662 buf2[1] = '\0';
06663 }
06664 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06665 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06666 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06667
06668 for (x = 0; x < 6; x++)
06669 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06670 keys[6] = 0;
06671 keys[7] = 0;
06672
06673
06674 if (vms->lastmsg < 0)
06675 keys[0] = 1;
06676 bytes += ast_adsi_set_keys(buf + bytes, keys);
06677
06678 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06679
06680 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06681 }
06682
06683 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06684 {
06685 unsigned char buf[256] = "";
06686 char buf1[256] = "", buf2[256] = "";
06687 int bytes = 0;
06688 unsigned char keys[8];
06689 int x;
06690
06691 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06692
06693 if (!ast_adsi_available(chan))
06694 return;
06695
06696
06697 for (x = 0; x < 6; x++)
06698 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06699
06700 keys[6] = 0;
06701 keys[7] = 0;
06702
06703 if ((vms->lastmsg + 1) < 1)
06704 keys[0] = 0;
06705
06706 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06707 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06708
06709 if (vms->lastmsg + 1)
06710 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06711 else
06712 strcpy(buf2, "no messages.");
06713 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06714 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06715 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06716 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06717 bytes += ast_adsi_set_keys(buf + bytes, keys);
06718
06719 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06720
06721 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06722
06723 }
06724
06725
06726
06727
06728
06729
06730
06731
06732
06733
06734
06735
06736
06737
06738
06739 static void adsi_goodbye(struct ast_channel *chan)
06740 {
06741 unsigned char buf[256];
06742 int bytes = 0;
06743
06744 if (!ast_adsi_available(chan))
06745 return;
06746 bytes += adsi_logo(buf + bytes);
06747 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06748 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06749 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06750 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06751
06752 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06753 }
06754
06755
06756
06757
06758
06759 static int get_folder(struct ast_channel *chan, int start)
06760 {
06761 int x;
06762 int d;
06763 char fn[PATH_MAX];
06764 d = ast_play_and_wait(chan, "vm-press");
06765 if (d)
06766 return d;
06767 for (x = start; x < 5; x++) {
06768 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06769 return d;
06770 d = ast_play_and_wait(chan, "vm-for");
06771 if (d)
06772 return d;
06773 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06774
06775
06776
06777
06778 if (x == 0) {
06779 if (ast_fileexists(fn, NULL, NULL)) {
06780 d = vm_play_folder_name(chan, fn);
06781 } else {
06782 ast_verb(1, "failed to find %s\n", fn);
06783 d = vm_play_folder_name(chan, "vm-INBOX");
06784 }
06785 } else {
06786 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06787 d = vm_play_folder_name(chan, fn);
06788 }
06789
06790 if (d)
06791 return d;
06792 d = ast_waitfordigit(chan, 500);
06793 if (d)
06794 return d;
06795 }
06796
06797 d = ast_play_and_wait(chan, "vm-tocancel");
06798 if (d)
06799 return d;
06800 d = ast_waitfordigit(chan, 4000);
06801 return d;
06802 }
06803
06804
06805
06806
06807
06808
06809
06810
06811
06812
06813
06814
06815
06816 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06817 {
06818 int res = 0;
06819 int loops = 0;
06820
06821 res = ast_play_and_wait(chan, fn);
06822 while (((res < '0') || (res > '9')) &&
06823 (res != '#') && (res >= 0) &&
06824 loops < 4) {
06825 res = get_folder(chan, 0);
06826 loops++;
06827 }
06828 if (loops == 4) {
06829 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06830 return '#';
06831 }
06832 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06833 return res;
06834 }
06835
06836
06837
06838
06839
06840
06841
06842
06843
06844
06845
06846
06847
06848
06849
06850
06851
06852
06853
06854 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06855 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06856 {
06857 int cmd = 0;
06858 int retries = 0, prepend_duration = 0, already_recorded = 0;
06859 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06860 char textfile[PATH_MAX];
06861 struct ast_config *msg_cfg;
06862 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06863 #ifndef IMAP_STORAGE
06864 signed char zero_gain = 0;
06865 #endif
06866 const char *duration_str;
06867
06868
06869 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06870 strcpy(textfile, msgfile);
06871 strcpy(backup, msgfile);
06872 strcpy(backup_textfile, msgfile);
06873 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06874 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06875 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06876
06877 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06878 *duration = atoi(duration_str);
06879 } else {
06880 *duration = 0;
06881 }
06882
06883 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06884 if (cmd)
06885 retries = 0;
06886 switch (cmd) {
06887 case '1':
06888
06889 #ifdef IMAP_STORAGE
06890
06891 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06892 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06893 ast_play_and_wait(chan, INTRO);
06894 ast_play_and_wait(chan, "beep");
06895 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06896 if (cmd == -1) {
06897 break;
06898 }
06899 cmd = 't';
06900 #else
06901
06902
06903
06904 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06905 strcpy(textfile, msgfile);
06906 strncat(textfile, ".txt", sizeof(textfile) - 1);
06907 *duration = 0;
06908
06909
06910 if (!msg_cfg) {
06911 cmd = 0;
06912 break;
06913 }
06914
06915
06916 #ifndef IMAP_STORAGE
06917 if (already_recorded) {
06918 ast_filecopy(backup, msgfile, NULL);
06919 copy(backup_textfile, textfile);
06920 }
06921 else {
06922 ast_filecopy(msgfile, backup, NULL);
06923 copy(textfile, backup_textfile);
06924 }
06925 #endif
06926 already_recorded = 1;
06927
06928 if (record_gain)
06929 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06930
06931 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06932
06933 if (cmd == 'S') {
06934 ast_stream_and_wait(chan, vm_pls_try_again, "");
06935 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06936 ast_filerename(backup, msgfile, NULL);
06937 }
06938
06939 if (record_gain)
06940 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06941
06942
06943 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06944 *duration = atoi(duration_str);
06945
06946 if (prepend_duration) {
06947 struct ast_category *msg_cat;
06948
06949 char duration_buf[12];
06950
06951 *duration += prepend_duration;
06952 msg_cat = ast_category_get(msg_cfg, "message");
06953 snprintf(duration_buf, 11, "%ld", *duration);
06954 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06955 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06956 }
06957 }
06958
06959 #endif
06960 break;
06961 case '2':
06962
06963 #ifdef IMAP_STORAGE
06964 *vms->introfn = '\0';
06965 #endif
06966 cmd = 't';
06967 break;
06968 case '*':
06969 cmd = '*';
06970 break;
06971 default:
06972
06973 already_recorded = 0;
06974
06975 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06976
06977 if (!cmd) {
06978 cmd = ast_play_and_wait(chan, "vm-starmain");
06979
06980 }
06981 if (!cmd) {
06982 cmd = ast_waitfordigit(chan, 6000);
06983 }
06984 if (!cmd) {
06985 retries++;
06986 }
06987 if (retries > 3) {
06988 cmd = '*';
06989 }
06990 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
06991 }
06992 }
06993
06994 if (msg_cfg)
06995 ast_config_destroy(msg_cfg);
06996 if (prepend_duration)
06997 *duration = prepend_duration;
06998
06999 if (already_recorded && cmd == -1) {
07000
07001 ast_filerename(backup, msgfile, NULL);
07002 rename(backup_textfile, textfile);
07003 }
07004
07005 if (cmd == 't' || cmd == 'S')
07006 cmd = 0;
07007 return cmd;
07008 }
07009
07010 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07011 {
07012 struct ast_event *event;
07013 char *mailbox, *context;
07014
07015
07016 context = mailbox = ast_strdupa(box);
07017 strsep(&context, "@");
07018 if (ast_strlen_zero(context))
07019 context = "default";
07020
07021 if (!(event = ast_event_new(AST_EVENT_MWI,
07022 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07023 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07024 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07025 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07026 AST_EVENT_IE_END))) {
07027 return;
07028 }
07029
07030 ast_event_queue_and_cache(event);
07031 }
07032
07033
07034
07035
07036
07037
07038
07039
07040
07041
07042
07043
07044
07045
07046
07047 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)
07048 {
07049 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07050 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07051 const char *category;
07052 char *myserveremail = serveremail;
07053
07054 ast_channel_lock(chan);
07055 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07056 category = ast_strdupa(category);
07057 }
07058 ast_channel_unlock(chan);
07059
07060 #ifndef IMAP_STORAGE
07061 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07062 #else
07063 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07064 #endif
07065 make_file(fn, sizeof(fn), todir, msgnum);
07066 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07067
07068 if (!ast_strlen_zero(vmu->attachfmt)) {
07069 if (strstr(fmt, vmu->attachfmt))
07070 fmt = vmu->attachfmt;
07071 else
07072 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);
07073 }
07074
07075
07076 fmt = ast_strdupa(fmt);
07077 stringp = fmt;
07078 strsep(&stringp, "|");
07079
07080 if (!ast_strlen_zero(vmu->serveremail))
07081 myserveremail = vmu->serveremail;
07082
07083 if (!ast_strlen_zero(vmu->email)) {
07084 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07085
07086 if (attach_user_voicemail)
07087 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07088
07089
07090 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07091
07092 if (attach_user_voicemail)
07093 DISPOSE(todir, msgnum);
07094 }
07095
07096 if (!ast_strlen_zero(vmu->pager)) {
07097 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07098 }
07099
07100 if (ast_test_flag(vmu, VM_DELETE))
07101 DELETE(todir, msgnum, fn, vmu);
07102
07103
07104 if (ast_app_has_voicemail(ext_context, NULL))
07105 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07106
07107 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07108
07109 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);
07110 run_externnotify(vmu->context, vmu->mailbox, flag);
07111
07112 #ifdef IMAP_STORAGE
07113 vm_delete(fn);
07114 if (ast_test_flag(vmu, VM_DELETE)) {
07115 vm_imap_delete(NULL, vms->curmsg, vmu);
07116 vms->newmessages--;
07117 }
07118 #endif
07119
07120 return 0;
07121 }
07122
07123
07124
07125
07126
07127
07128
07129
07130
07131
07132
07133
07134
07135
07136
07137
07138
07139
07140
07141
07142
07143
07144
07145
07146
07147
07148
07149
07150 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)
07151 {
07152 #ifdef IMAP_STORAGE
07153 int todircount = 0;
07154 struct vm_state *dstvms;
07155 #endif
07156 char username[70]="";
07157 char fn[PATH_MAX];
07158 char ecodes[16] = "#";
07159 int res = 0, cmd = 0;
07160 struct ast_vm_user *receiver = NULL, *vmtmp;
07161 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07162 char *stringp;
07163 const char *s;
07164 int saved_messages = 0;
07165 int valid_extensions = 0;
07166 char *dir;
07167 int curmsg;
07168 char urgent_str[7] = "";
07169 int prompt_played = 0;
07170 #ifndef IMAP_STORAGE
07171 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07172 #endif
07173 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07174 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07175 }
07176
07177 if (vms == NULL) return -1;
07178 dir = vms->curdir;
07179 curmsg = vms->curmsg;
07180
07181 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07182 while (!res && !valid_extensions) {
07183 int use_directory = 0;
07184 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07185 int done = 0;
07186 int retries = 0;
07187 cmd = 0;
07188 while ((cmd >= 0) && !done ){
07189 if (cmd)
07190 retries = 0;
07191 switch (cmd) {
07192 case '1':
07193 use_directory = 0;
07194 done = 1;
07195 break;
07196 case '2':
07197 use_directory = 1;
07198 done = 1;
07199 break;
07200 case '*':
07201 cmd = 't';
07202 done = 1;
07203 break;
07204 default:
07205
07206 cmd = ast_play_and_wait(chan, "vm-forward");
07207 if (!cmd) {
07208 cmd = ast_waitfordigit(chan, 3000);
07209 }
07210 if (!cmd) {
07211 retries++;
07212 }
07213 if (retries > 3) {
07214 cmd = 't';
07215 done = 1;
07216 }
07217 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07218 }
07219 }
07220 if (cmd < 0 || cmd == 't')
07221 break;
07222 }
07223
07224 if (use_directory) {
07225
07226
07227 char old_context[sizeof(chan->context)];
07228 char old_exten[sizeof(chan->exten)];
07229 int old_priority;
07230 struct ast_app* directory_app;
07231
07232 directory_app = pbx_findapp("Directory");
07233 if (directory_app) {
07234 char vmcontext[256];
07235
07236 memcpy(old_context, chan->context, sizeof(chan->context));
07237 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07238 old_priority = chan->priority;
07239
07240
07241 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07242 res = pbx_exec(chan, directory_app, vmcontext);
07243
07244 ast_copy_string(username, chan->exten, sizeof(username));
07245
07246
07247 memcpy(chan->context, old_context, sizeof(chan->context));
07248 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07249 chan->priority = old_priority;
07250 } else {
07251 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07252 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07253 }
07254 } else {
07255
07256 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07257 res = ast_streamfile(chan, "vm-extension", chan->language);
07258 prompt_played++;
07259 if (res || prompt_played > 4)
07260 break;
07261 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07262 break;
07263 }
07264
07265
07266 if (ast_strlen_zero(username))
07267 continue;
07268 stringp = username;
07269 s = strsep(&stringp, "*");
07270
07271 valid_extensions = 1;
07272 while (s) {
07273 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07274 int oldmsgs;
07275 int newmsgs;
07276 int capacity;
07277 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07278 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07279
07280 res = ast_play_and_wait(chan, "pbx-invalid");
07281 valid_extensions = 0;
07282 break;
07283 }
07284 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07285 if ((newmsgs + oldmsgs) >= capacity) {
07286 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07287 res = ast_play_and_wait(chan, "vm-mailboxfull");
07288 valid_extensions = 0;
07289 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07290 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07291 free_user(vmtmp);
07292 }
07293 inprocess_count(receiver->mailbox, receiver->context, -1);
07294 break;
07295 }
07296 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07297 } else {
07298
07299
07300
07301
07302
07303 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07304 free_user(receiver);
07305 }
07306 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07307
07308 res = ast_play_and_wait(chan, "pbx-invalid");
07309 valid_extensions = 0;
07310 break;
07311 }
07312
07313
07314 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07315 RETRIEVE(fn, -1, s, receiver->context);
07316 if (ast_fileexists(fn, NULL, NULL) > 0) {
07317 res = ast_stream_and_wait(chan, fn, ecodes);
07318 if (res) {
07319 DISPOSE(fn, -1);
07320 return res;
07321 }
07322 } else {
07323 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07324 }
07325 DISPOSE(fn, -1);
07326
07327 s = strsep(&stringp, "*");
07328 }
07329
07330 if (valid_extensions)
07331 break;
07332 }
07333
07334 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07335 return res;
07336 if (is_new_message == 1) {
07337 struct leave_vm_options leave_options;
07338 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07339 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07340
07341
07342 memset(&leave_options, 0, sizeof(leave_options));
07343 leave_options.record_gain = record_gain;
07344 cmd = leave_voicemail(chan, mailbox, &leave_options);
07345 } else {
07346
07347 long duration = 0;
07348 struct vm_state vmstmp;
07349 int copy_msg_result = 0;
07350 memcpy(&vmstmp, vms, sizeof(vmstmp));
07351
07352 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07353
07354 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07355 if (!cmd) {
07356 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07357 #ifdef IMAP_STORAGE
07358 int attach_user_voicemail;
07359 char *myserveremail = serveremail;
07360
07361
07362 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07363 if (!dstvms) {
07364 dstvms = create_vm_state_from_user(vmtmp);
07365 }
07366 if (dstvms) {
07367 init_mailstream(dstvms, 0);
07368 if (!dstvms->mailstream) {
07369 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07370 } else {
07371 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07372 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07373 }
07374 } else {
07375 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07376 }
07377 if (!ast_strlen_zero(vmtmp->serveremail))
07378 myserveremail = vmtmp->serveremail;
07379 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07380
07381 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07382 dstvms->curbox,
07383 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07384 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07385 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07386 NULL, urgent_str);
07387 #else
07388 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07389 #endif
07390 saved_messages++;
07391 AST_LIST_REMOVE_CURRENT(list);
07392 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07393 free_user(vmtmp);
07394 if (res)
07395 break;
07396 }
07397 AST_LIST_TRAVERSE_SAFE_END;
07398 if (saved_messages > 0 && !copy_msg_result) {
07399
07400
07401
07402
07403
07404
07405
07406
07407 #ifdef IMAP_STORAGE
07408
07409 if (ast_strlen_zero(vmstmp.introfn))
07410 #endif
07411 res = ast_play_and_wait(chan, "vm-msgsaved");
07412 }
07413 #ifndef IMAP_STORAGE
07414 else {
07415
07416 res = ast_play_and_wait(chan, "vm-mailboxfull");
07417 }
07418
07419 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07420 strcpy(textfile, msgfile);
07421 strcpy(backup, msgfile);
07422 strcpy(backup_textfile, msgfile);
07423 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07424 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07425 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07426 if (ast_fileexists(backup, NULL, NULL) > 0) {
07427 ast_filerename(backup, msgfile, NULL);
07428 rename(backup_textfile, textfile);
07429 }
07430 #endif
07431 }
07432 DISPOSE(dir, curmsg);
07433 #ifndef IMAP_STORAGE
07434 if (cmd) {
07435 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07436 strcpy(textfile, msgfile);
07437 strcpy(backup_textfile, msgfile);
07438 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07439 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07440 rename(backup_textfile, textfile);
07441 }
07442 #endif
07443 }
07444
07445
07446 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07447 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07448 free_user(vmtmp);
07449 }
07450 return res ? res : cmd;
07451 }
07452
07453 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07454 {
07455 int res;
07456 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07457 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07458 return res;
07459 }
07460
07461 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07462 {
07463 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07464 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);
07465 }
07466
07467 static int play_message_category(struct ast_channel *chan, const char *category)
07468 {
07469 int res = 0;
07470
07471 if (!ast_strlen_zero(category))
07472 res = ast_play_and_wait(chan, category);
07473
07474 if (res) {
07475 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07476 res = 0;
07477 }
07478
07479 return res;
07480 }
07481
07482 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07483 {
07484 int res = 0;
07485 struct vm_zone *the_zone = NULL;
07486 time_t t;
07487
07488 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07489 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07490 return 0;
07491 }
07492
07493
07494 if (!ast_strlen_zero(vmu->zonetag)) {
07495
07496 struct vm_zone *z;
07497 AST_LIST_LOCK(&zones);
07498 AST_LIST_TRAVERSE(&zones, z, list) {
07499 if (!strcmp(z->name, vmu->zonetag)) {
07500 the_zone = z;
07501 break;
07502 }
07503 }
07504 AST_LIST_UNLOCK(&zones);
07505 }
07506
07507
07508 #if 0
07509
07510 ast_localtime(&t, &time_now, NULL);
07511 tv_now = ast_tvnow();
07512 ast_localtime(&tv_now, &time_then, NULL);
07513
07514
07515 if (time_now.tm_year == time_then.tm_year)
07516 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07517 else
07518 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07519 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07520
07521
07522 #endif
07523 if (the_zone) {
07524 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07525 } else if (!strncasecmp(chan->language, "de", 2)) {
07526 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07527 } else if (!strncasecmp(chan->language, "gr", 2)) {
07528 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07529 } else if (!strncasecmp(chan->language, "it", 2)) {
07530 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);
07531 } else if (!strncasecmp(chan->language, "nl", 2)) {
07532 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07533 } else if (!strncasecmp(chan->language, "no", 2)) {
07534 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07535 } else if (!strncasecmp(chan->language, "pl", 2)) {
07536 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07537 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07538 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);
07539 } else if (!strncasecmp(chan->language, "se", 2)) {
07540 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07541 } else if (!strncasecmp(chan->language, "zh", 2)) {
07542 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07543 } else if (!strncasecmp(chan->language, "vi", 2)) {
07544 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);
07545 } else {
07546 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07547 }
07548 #if 0
07549 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07550 #endif
07551 return res;
07552 }
07553
07554
07555
07556 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07557 {
07558 int res = 0;
07559 int i;
07560 char *callerid, *name;
07561 char prefile[PATH_MAX] = "";
07562
07563
07564
07565
07566
07567
07568
07569
07570
07571 if ((cid == NULL)||(context == NULL))
07572 return res;
07573
07574
07575 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07576 ast_callerid_parse(cid, &name, &callerid);
07577 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07578
07579
07580 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07581 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07582 if ((strcmp(cidinternalcontexts[i], context) == 0))
07583 break;
07584 }
07585 if (i != MAX_NUM_CID_CONTEXTS){
07586 if (!res) {
07587 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07588 if (!ast_strlen_zero(prefile)) {
07589
07590 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07591 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07592 if (!callback)
07593 res = wait_file2(chan, vms, "vm-from");
07594 res = ast_stream_and_wait(chan, prefile, "");
07595 } else {
07596 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07597
07598 if (!callback)
07599 res = wait_file2(chan, vms, "vm-from-extension");
07600 res = ast_say_digit_str(chan, callerid, "", chan->language);
07601 }
07602 }
07603 }
07604 } else if (!res) {
07605 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07606
07607 if (!callback)
07608 res = wait_file2(chan, vms, "vm-from-phonenumber");
07609 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07610 }
07611 } else {
07612
07613 ast_debug(1, "VM-CID: From an unknown number\n");
07614
07615 res = wait_file2(chan, vms, "vm-unknown-caller");
07616 }
07617 return res;
07618 }
07619
07620 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07621 {
07622 int res = 0;
07623 int durationm;
07624 int durations;
07625
07626 if (duration == NULL)
07627 return res;
07628
07629
07630 durations = atoi(duration);
07631 durationm = (durations / 60);
07632
07633 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07634
07635 if ((!res) && (durationm >= minduration)) {
07636 res = wait_file2(chan, vms, "vm-duration");
07637
07638
07639 if (!strncasecmp(chan->language, "pl", 2)) {
07640 div_t num = div(durationm, 10);
07641
07642 if (durationm == 1) {
07643 res = ast_play_and_wait(chan, "digits/1z");
07644 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07645 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07646 if (num.rem == 2) {
07647 if (!num.quot) {
07648 res = ast_play_and_wait(chan, "digits/2-ie");
07649 } else {
07650 res = say_and_wait(chan, durationm - 2 , chan->language);
07651 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07652 }
07653 } else {
07654 res = say_and_wait(chan, durationm, chan->language);
07655 }
07656 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07657 } else {
07658 res = say_and_wait(chan, durationm, chan->language);
07659 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07660 }
07661
07662 } else {
07663 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07664 res = wait_file2(chan, vms, "vm-minutes");
07665 }
07666 }
07667 return res;
07668 }
07669
07670 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07671 {
07672 int res = 0;
07673 char filename[256], *cid;
07674 const char *origtime, *context, *category, *duration, *flag;
07675 struct ast_config *msg_cfg;
07676 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07677
07678 vms->starting = 0;
07679 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07680 adsi_message(chan, vms);
07681 if (!vms->curmsg) {
07682 res = wait_file2(chan, vms, "vm-first");
07683 } else if (vms->curmsg == vms->lastmsg) {
07684 res = wait_file2(chan, vms, "vm-last");
07685 }
07686
07687 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07688 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07689 msg_cfg = ast_config_load(filename, config_flags);
07690 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07691 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07692 return 0;
07693 }
07694 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07695
07696
07697 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07698 res = wait_file2(chan, vms, "vm-Urgent");
07699 }
07700
07701 if (!res) {
07702
07703
07704 if (!strncasecmp(chan->language, "pl", 2)) {
07705 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07706 int ten, one;
07707 char nextmsg[256];
07708 ten = (vms->curmsg + 1) / 10;
07709 one = (vms->curmsg + 1) % 10;
07710
07711 if (vms->curmsg < 20) {
07712 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07713 res = wait_file2(chan, vms, nextmsg);
07714 } else {
07715 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07716 res = wait_file2(chan, vms, nextmsg);
07717 if (one > 0) {
07718 if (!res) {
07719 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07720 res = wait_file2(chan, vms, nextmsg);
07721 }
07722 }
07723 }
07724 }
07725 if (!res)
07726 res = wait_file2(chan, vms, "vm-message");
07727
07728 } else if (!strncasecmp(chan->language, "he", 2)) {
07729 if (!vms->curmsg) {
07730 res = wait_file2(chan, vms, "vm-message");
07731 res = wait_file2(chan, vms, "vm-first");
07732 } else if (vms->curmsg == vms->lastmsg) {
07733 res = wait_file2(chan, vms, "vm-message");
07734 res = wait_file2(chan, vms, "vm-last");
07735 } else {
07736 res = wait_file2(chan, vms, "vm-message");
07737 res = wait_file2(chan, vms, "vm-number");
07738 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07739 }
07740
07741 } else if (!strncasecmp(chan->language, "vi", 2)) {
07742 if (!vms->curmsg) {
07743 res = wait_file2(chan, vms, "vm-message");
07744 res = wait_file2(chan, vms, "vm-first");
07745 } else if (vms->curmsg == vms->lastmsg) {
07746 res = wait_file2(chan, vms, "vm-message");
07747 res = wait_file2(chan, vms, "vm-last");
07748 } else {
07749 res = wait_file2(chan, vms, "vm-message");
07750 res = wait_file2(chan, vms, "vm-number");
07751 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07752 }
07753 } else {
07754 if (!strncasecmp(chan->language, "se", 2)) {
07755 res = wait_file2(chan, vms, "vm-meddelandet");
07756 } else {
07757 res = wait_file2(chan, vms, "vm-message");
07758 }
07759 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07760 if (!res) {
07761 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07762 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07763 }
07764 }
07765 }
07766 }
07767
07768 if (!msg_cfg) {
07769 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07770 return 0;
07771 }
07772
07773 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07774 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07775 DISPOSE(vms->curdir, vms->curmsg);
07776 ast_config_destroy(msg_cfg);
07777 return 0;
07778 }
07779
07780 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07781 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07782 category = ast_variable_retrieve(msg_cfg, "message", "category");
07783
07784 context = ast_variable_retrieve(msg_cfg, "message", "context");
07785 if (!strncasecmp("macro", context, 5))
07786 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07787 if (!res) {
07788 res = play_message_category(chan, category);
07789 }
07790 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07791 res = play_message_datetime(chan, vmu, origtime, filename);
07792 }
07793 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07794 res = play_message_callerid(chan, vms, cid, context, 0);
07795 }
07796 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07797 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07798 }
07799
07800 if (res == '1') {
07801 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07802 res = 0;
07803 }
07804 ast_config_destroy(msg_cfg);
07805
07806 if (!res) {
07807 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07808 #ifdef IMAP_STORAGE
07809 ast_mutex_lock(&vms->lock);
07810 #endif
07811 vms->heard[vms->curmsg] = 1;
07812 #ifdef IMAP_STORAGE
07813 ast_mutex_unlock(&vms->lock);
07814
07815
07816
07817 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07818 wait_file(chan, vms, vms->introfn);
07819 }
07820 #endif
07821 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07822 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07823 res = 0;
07824 }
07825 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07826 }
07827 DISPOSE(vms->curdir, vms->curmsg);
07828 return res;
07829 }
07830
07831 #ifdef IMAP_STORAGE
07832 static int imap_remove_file(char *dir, int msgnum)
07833 {
07834 char fn[PATH_MAX];
07835 char full_fn[PATH_MAX];
07836 char intro[PATH_MAX] = {0,};
07837
07838 if (msgnum > -1) {
07839 make_file(fn, sizeof(fn), dir, msgnum);
07840 snprintf(intro, sizeof(intro), "%sintro", fn);
07841 } else
07842 ast_copy_string(fn, dir, sizeof(fn));
07843
07844 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07845 ast_filedelete(fn, NULL);
07846 if (!ast_strlen_zero(intro)) {
07847 ast_filedelete(intro, NULL);
07848 }
07849 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07850 unlink(full_fn);
07851 }
07852 return 0;
07853 }
07854
07855
07856
07857 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07858 {
07859 char *file, *filename;
07860 char *attachment;
07861 char arg[10];
07862 int i;
07863 BODY* body;
07864
07865 file = strrchr(ast_strdupa(dir), '/');
07866 if (file) {
07867 *file++ = '\0';
07868 } else {
07869 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07870 return -1;
07871 }
07872
07873 ast_mutex_lock(&vms->lock);
07874 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07875 mail_fetchstructure(vms->mailstream, i + 1, &body);
07876
07877 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07878 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07879 } else {
07880 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07881 ast_mutex_unlock(&vms->lock);
07882 return -1;
07883 }
07884 filename = strsep(&attachment, ".");
07885 if (!strcmp(filename, file)) {
07886 sprintf(arg, "%d", i + 1);
07887 mail_setflag(vms->mailstream, arg, "\\DELETED");
07888 }
07889 }
07890 mail_expunge(vms->mailstream);
07891 ast_mutex_unlock(&vms->lock);
07892 return 0;
07893 }
07894
07895 #elif !defined(IMAP_STORAGE)
07896 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07897 {
07898 int count_msg, last_msg;
07899
07900 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07901
07902
07903
07904
07905 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07906
07907
07908 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07909
07910
07911 count_msg = count_messages(vmu, vms->curdir);
07912 if (count_msg < 0) {
07913 return count_msg;
07914 } else {
07915 vms->lastmsg = count_msg - 1;
07916 }
07917
07918 if (vm_allocate_dh(vms, vmu, count_msg)) {
07919 return -1;
07920 }
07921
07922
07923
07924
07925
07926
07927
07928
07929 if (vm_lock_path(vms->curdir)) {
07930 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07931 return ERROR_LOCK_PATH;
07932 }
07933
07934
07935 last_msg = last_message_index(vmu, vms->curdir);
07936 ast_unlock_path(vms->curdir);
07937
07938 if (last_msg < -1) {
07939 return last_msg;
07940 } else if (vms->lastmsg != last_msg) {
07941 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);
07942 resequence_mailbox(vmu, vms->curdir, count_msg);
07943 }
07944
07945 return 0;
07946 }
07947 #endif
07948
07949 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07950 {
07951 int x = 0;
07952 int last_msg_idx = 0;
07953
07954 #ifndef IMAP_STORAGE
07955 int res = 0, nummsg;
07956 char fn2[PATH_MAX];
07957 #endif
07958
07959 if (vms->lastmsg <= -1) {
07960 goto done;
07961 }
07962
07963 vms->curmsg = -1;
07964 #ifndef IMAP_STORAGE
07965
07966 if (vm_lock_path(vms->curdir)) {
07967 return ERROR_LOCK_PATH;
07968 }
07969
07970
07971 last_msg_idx = last_message_index(vmu, vms->curdir);
07972 if (last_msg_idx != vms->lastmsg) {
07973 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
07974 }
07975
07976
07977 for (x = 0; x < last_msg_idx + 1; x++) {
07978 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07979
07980 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07981 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07982 break;
07983 }
07984 vms->curmsg++;
07985 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07986 if (strcmp(vms->fn, fn2)) {
07987 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07988 }
07989 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07990
07991 res = save_to_folder(vmu, vms, x, 1);
07992 if (res == ERROR_LOCK_PATH) {
07993
07994 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07995 vms->deleted[x] = 0;
07996 vms->heard[x] = 0;
07997 --x;
07998 }
07999 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08000
08001 res = save_to_folder(vmu, vms, x, 10);
08002 if (res == ERROR_LOCK_PATH) {
08003
08004 vms->deleted[x] = 0;
08005 vms->heard[x] = 0;
08006 --x;
08007 }
08008 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08009
08010
08011 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08012 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08013 DELETE(vms->curdir, x, vms->fn, vmu);
08014 }
08015 }
08016 }
08017
08018
08019 nummsg = x - 1;
08020 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08021 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08022 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08023 DELETE(vms->curdir, x, vms->fn, vmu);
08024 }
08025 }
08026 ast_unlock_path(vms->curdir);
08027 #else
08028 ast_mutex_lock(&vms->lock);
08029 if (vms->deleted) {
08030
08031
08032 last_msg_idx = vms->dh_arraysize;
08033 for (x = last_msg_idx - 1; x >= 0; x--) {
08034 if (vms->deleted[x]) {
08035 ast_debug(3, "IMAP delete of %d\n", x);
08036 DELETE(vms->curdir, x, vms->fn, vmu);
08037 }
08038 }
08039 }
08040 #endif
08041
08042 done:
08043 if (vms->deleted) {
08044 ast_free(vms->deleted);
08045 vms->deleted = NULL;
08046 }
08047 if (vms->heard) {
08048 ast_free(vms->heard);
08049 vms->heard = NULL;
08050 }
08051 vms->dh_arraysize = 0;
08052 #ifdef IMAP_STORAGE
08053 ast_mutex_unlock(&vms->lock);
08054 #endif
08055
08056 return 0;
08057 }
08058
08059
08060
08061
08062
08063
08064
08065 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08066 {
08067 int cmd;
08068 char *buf;
08069
08070 buf = ast_alloca(strlen(box) + 2);
08071 strcpy(buf, box);
08072 strcat(buf, "s");
08073
08074 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08075 cmd = ast_play_and_wait(chan, buf);
08076 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08077 } else {
08078 cmd = ast_play_and_wait(chan, "vm-messages");
08079 return cmd ? cmd : ast_play_and_wait(chan, box);
08080 }
08081 }
08082
08083 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08084 {
08085 int cmd;
08086
08087 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08088 if (!strcasecmp(box, "vm-INBOX"))
08089 cmd = ast_play_and_wait(chan, "vm-new-e");
08090 else
08091 cmd = ast_play_and_wait(chan, "vm-old-e");
08092 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08093 } else {
08094 cmd = ast_play_and_wait(chan, "vm-messages");
08095 return cmd ? cmd : ast_play_and_wait(chan, box);
08096 }
08097 }
08098
08099 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08100 {
08101 int cmd;
08102
08103 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08104 cmd = ast_play_and_wait(chan, "vm-messages");
08105 return cmd ? cmd : ast_play_and_wait(chan, box);
08106 } else {
08107 cmd = ast_play_and_wait(chan, box);
08108 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08109 }
08110 }
08111
08112 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08113 {
08114 int cmd;
08115
08116 if ( !strncasecmp(chan->language, "it", 2) ||
08117 !strncasecmp(chan->language, "es", 2) ||
08118 !strncasecmp(chan->language, "pt", 2)) {
08119 cmd = ast_play_and_wait(chan, "vm-messages");
08120 return cmd ? cmd : ast_play_and_wait(chan, box);
08121 } else if (!strncasecmp(chan->language, "gr", 2)) {
08122 return vm_play_folder_name_gr(chan, box);
08123 } else if (!strncasecmp(chan->language, "he", 2)) {
08124 return ast_play_and_wait(chan, box);
08125 } else if (!strncasecmp(chan->language, "pl", 2)) {
08126 return vm_play_folder_name_pl(chan, box);
08127 } else if (!strncasecmp(chan->language, "ua", 2)) {
08128 return vm_play_folder_name_ua(chan, box);
08129 } else if (!strncasecmp(chan->language, "vi", 2)) {
08130 return ast_play_and_wait(chan, box);
08131 } else {
08132 cmd = ast_play_and_wait(chan, box);
08133 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08134 }
08135 }
08136
08137
08138
08139
08140
08141
08142
08143
08144
08145
08146
08147
08148
08149 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08150 {
08151 int res = 0;
08152
08153 if (vms->newmessages) {
08154 res = ast_play_and_wait(chan, "vm-youhave");
08155 if (!res)
08156 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08157 if (!res) {
08158 if ((vms->newmessages == 1)) {
08159 res = ast_play_and_wait(chan, "vm-INBOX");
08160 if (!res)
08161 res = ast_play_and_wait(chan, "vm-message");
08162 } else {
08163 res = ast_play_and_wait(chan, "vm-INBOXs");
08164 if (!res)
08165 res = ast_play_and_wait(chan, "vm-messages");
08166 }
08167 }
08168 } else if (vms->oldmessages){
08169 res = ast_play_and_wait(chan, "vm-youhave");
08170 if (!res)
08171 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08172 if ((vms->oldmessages == 1)){
08173 res = ast_play_and_wait(chan, "vm-Old");
08174 if (!res)
08175 res = ast_play_and_wait(chan, "vm-message");
08176 } else {
08177 res = ast_play_and_wait(chan, "vm-Olds");
08178 if (!res)
08179 res = ast_play_and_wait(chan, "vm-messages");
08180 }
08181 } else if (!vms->oldmessages && !vms->newmessages)
08182 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08183 return res;
08184 }
08185
08186
08187
08188
08189
08190
08191
08192
08193
08194
08195
08196
08197
08198
08199
08200
08201
08202
08203
08204
08205
08206
08207
08208
08209
08210
08211
08212
08213
08214
08215
08216
08217
08218
08219
08220
08221
08222
08223
08224
08225
08226
08227
08228
08229
08230
08231
08232
08233
08234
08235
08236
08237
08238
08239
08240
08241
08242
08243 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08244 {
08245 int res;
08246 int lastnum = 0;
08247
08248 res = ast_play_and_wait(chan, "vm-youhave");
08249
08250 if (!res && vms->newmessages) {
08251 lastnum = vms->newmessages;
08252
08253 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08254 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08255 }
08256
08257 if (!res && vms->oldmessages) {
08258 res = ast_play_and_wait(chan, "vm-and");
08259 }
08260 }
08261
08262 if (!res && vms->oldmessages) {
08263 lastnum = vms->oldmessages;
08264
08265 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08266 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08267 }
08268 }
08269
08270 if (!res) {
08271 if (lastnum == 0) {
08272 res = ast_play_and_wait(chan, "vm-no");
08273 }
08274 if (!res) {
08275 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08276 }
08277 }
08278
08279 return res;
08280 }
08281
08282
08283 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08284 {
08285 int res = 0;
08286
08287
08288 if (!res) {
08289 if ((vms->newmessages) || (vms->oldmessages)) {
08290 res = ast_play_and_wait(chan, "vm-youhave");
08291 }
08292
08293
08294
08295
08296
08297 if (vms->newmessages) {
08298 if (!res) {
08299 if (vms->newmessages == 1) {
08300 res = ast_play_and_wait(chan, "vm-INBOX1");
08301 } else {
08302 if (vms->newmessages == 2) {
08303 res = ast_play_and_wait(chan, "vm-shtei");
08304 } else {
08305 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08306 }
08307 res = ast_play_and_wait(chan, "vm-INBOX");
08308 }
08309 }
08310 if (vms->oldmessages && !res) {
08311 res = ast_play_and_wait(chan, "vm-and");
08312 if (vms->oldmessages == 1) {
08313 res = ast_play_and_wait(chan, "vm-Old1");
08314 } else {
08315 if (vms->oldmessages == 2) {
08316 res = ast_play_and_wait(chan, "vm-shtei");
08317 } else {
08318 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08319 }
08320 res = ast_play_and_wait(chan, "vm-Old");
08321 }
08322 }
08323 }
08324 if (!res && vms->oldmessages && !vms->newmessages) {
08325 if (!res) {
08326 if (vms->oldmessages == 1) {
08327 res = ast_play_and_wait(chan, "vm-Old1");
08328 } else {
08329 if (vms->oldmessages == 2) {
08330 res = ast_play_and_wait(chan, "vm-shtei");
08331 } else {
08332 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08333 }
08334 res = ast_play_and_wait(chan, "vm-Old");
08335 }
08336 }
08337 }
08338 if (!res) {
08339 if (!vms->oldmessages && !vms->newmessages) {
08340 if (!res) {
08341 res = ast_play_and_wait(chan, "vm-nomessages");
08342 }
08343 }
08344 }
08345 }
08346 return res;
08347 }
08348
08349
08350 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08351 {
08352 int res;
08353
08354
08355 res = ast_play_and_wait(chan, "vm-youhave");
08356 if (!res) {
08357 if (vms->urgentmessages) {
08358 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08359 if (!res)
08360 res = ast_play_and_wait(chan, "vm-Urgent");
08361 if ((vms->oldmessages || vms->newmessages) && !res) {
08362 res = ast_play_and_wait(chan, "vm-and");
08363 } else if (!res) {
08364 if ((vms->urgentmessages == 1))
08365 res = ast_play_and_wait(chan, "vm-message");
08366 else
08367 res = ast_play_and_wait(chan, "vm-messages");
08368 }
08369 }
08370 if (vms->newmessages) {
08371 res = say_and_wait(chan, vms->newmessages, chan->language);
08372 if (!res)
08373 res = ast_play_and_wait(chan, "vm-INBOX");
08374 if (vms->oldmessages && !res)
08375 res = ast_play_and_wait(chan, "vm-and");
08376 else if (!res) {
08377 if ((vms->newmessages == 1))
08378 res = ast_play_and_wait(chan, "vm-message");
08379 else
08380 res = ast_play_and_wait(chan, "vm-messages");
08381 }
08382
08383 }
08384 if (!res && vms->oldmessages) {
08385 res = say_and_wait(chan, vms->oldmessages, chan->language);
08386 if (!res)
08387 res = ast_play_and_wait(chan, "vm-Old");
08388 if (!res) {
08389 if (vms->oldmessages == 1)
08390 res = ast_play_and_wait(chan, "vm-message");
08391 else
08392 res = ast_play_and_wait(chan, "vm-messages");
08393 }
08394 }
08395 if (!res) {
08396 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08397 res = ast_play_and_wait(chan, "vm-no");
08398 if (!res)
08399 res = ast_play_and_wait(chan, "vm-messages");
08400 }
08401 }
08402 }
08403 return res;
08404 }
08405
08406
08407 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08408 {
08409
08410 int res;
08411 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08412 res = ast_play_and_wait(chan, "vm-no") ||
08413 ast_play_and_wait(chan, "vm-message");
08414 else
08415 res = ast_play_and_wait(chan, "vm-youhave");
08416 if (!res && vms->newmessages) {
08417 res = (vms->newmessages == 1) ?
08418 ast_play_and_wait(chan, "digits/un") ||
08419 ast_play_and_wait(chan, "vm-nuovo") ||
08420 ast_play_and_wait(chan, "vm-message") :
08421
08422 say_and_wait(chan, vms->newmessages, chan->language) ||
08423 ast_play_and_wait(chan, "vm-nuovi") ||
08424 ast_play_and_wait(chan, "vm-messages");
08425 if (!res && vms->oldmessages)
08426 res = ast_play_and_wait(chan, "vm-and");
08427 }
08428 if (!res && vms->oldmessages) {
08429 res = (vms->oldmessages == 1) ?
08430 ast_play_and_wait(chan, "digits/un") ||
08431 ast_play_and_wait(chan, "vm-vecchio") ||
08432 ast_play_and_wait(chan, "vm-message") :
08433
08434 say_and_wait(chan, vms->oldmessages, chan->language) ||
08435 ast_play_and_wait(chan, "vm-vecchi") ||
08436 ast_play_and_wait(chan, "vm-messages");
08437 }
08438 return res;
08439 }
08440
08441
08442 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08443 {
08444
08445 int res;
08446 div_t num;
08447
08448 if (!vms->oldmessages && !vms->newmessages) {
08449 res = ast_play_and_wait(chan, "vm-no");
08450 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08451 return res;
08452 } else {
08453 res = ast_play_and_wait(chan, "vm-youhave");
08454 }
08455
08456 if (vms->newmessages) {
08457 num = div(vms->newmessages, 10);
08458 if (vms->newmessages == 1) {
08459 res = ast_play_and_wait(chan, "digits/1-a");
08460 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08461 res = res ? res : ast_play_and_wait(chan, "vm-message");
08462 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08463 if (num.rem == 2) {
08464 if (!num.quot) {
08465 res = ast_play_and_wait(chan, "digits/2-ie");
08466 } else {
08467 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08468 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08469 }
08470 } else {
08471 res = say_and_wait(chan, vms->newmessages, chan->language);
08472 }
08473 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08474 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08475 } else {
08476 res = say_and_wait(chan, vms->newmessages, chan->language);
08477 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08478 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08479 }
08480 if (!res && vms->oldmessages)
08481 res = ast_play_and_wait(chan, "vm-and");
08482 }
08483 if (!res && vms->oldmessages) {
08484 num = div(vms->oldmessages, 10);
08485 if (vms->oldmessages == 1) {
08486 res = ast_play_and_wait(chan, "digits/1-a");
08487 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08488 res = res ? res : ast_play_and_wait(chan, "vm-message");
08489 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08490 if (num.rem == 2) {
08491 if (!num.quot) {
08492 res = ast_play_and_wait(chan, "digits/2-ie");
08493 } else {
08494 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08495 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08496 }
08497 } else {
08498 res = say_and_wait(chan, vms->oldmessages, chan->language);
08499 }
08500 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08501 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08502 } else {
08503 res = say_and_wait(chan, vms->oldmessages, chan->language);
08504 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08505 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08506 }
08507 }
08508
08509 return res;
08510 }
08511
08512
08513 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08514 {
08515
08516 int res;
08517
08518 res = ast_play_and_wait(chan, "vm-youhave");
08519 if (res)
08520 return res;
08521
08522 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08523 res = ast_play_and_wait(chan, "vm-no");
08524 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08525 return res;
08526 }
08527
08528 if (vms->newmessages) {
08529 if ((vms->newmessages == 1)) {
08530 res = ast_play_and_wait(chan, "digits/ett");
08531 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08532 res = res ? res : ast_play_and_wait(chan, "vm-message");
08533 } else {
08534 res = say_and_wait(chan, vms->newmessages, chan->language);
08535 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08536 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08537 }
08538 if (!res && vms->oldmessages)
08539 res = ast_play_and_wait(chan, "vm-and");
08540 }
08541 if (!res && vms->oldmessages) {
08542 if (vms->oldmessages == 1) {
08543 res = ast_play_and_wait(chan, "digits/ett");
08544 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08545 res = res ? res : ast_play_and_wait(chan, "vm-message");
08546 } else {
08547 res = say_and_wait(chan, vms->oldmessages, chan->language);
08548 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08549 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08550 }
08551 }
08552
08553 return res;
08554 }
08555
08556
08557 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08558 {
08559
08560 int res;
08561
08562 res = ast_play_and_wait(chan, "vm-youhave");
08563 if (res)
08564 return res;
08565
08566 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08567 res = ast_play_and_wait(chan, "vm-no");
08568 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08569 return res;
08570 }
08571
08572 if (vms->newmessages) {
08573 if ((vms->newmessages == 1)) {
08574 res = ast_play_and_wait(chan, "digits/1");
08575 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08576 res = res ? res : ast_play_and_wait(chan, "vm-message");
08577 } else {
08578 res = say_and_wait(chan, vms->newmessages, chan->language);
08579 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08580 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08581 }
08582 if (!res && vms->oldmessages)
08583 res = ast_play_and_wait(chan, "vm-and");
08584 }
08585 if (!res && vms->oldmessages) {
08586 if (vms->oldmessages == 1) {
08587 res = ast_play_and_wait(chan, "digits/1");
08588 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08589 res = res ? res : ast_play_and_wait(chan, "vm-message");
08590 } else {
08591 res = say_and_wait(chan, vms->oldmessages, chan->language);
08592 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08593 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08594 }
08595 }
08596
08597 return res;
08598 }
08599
08600
08601 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08602 {
08603
08604 int res;
08605 res = ast_play_and_wait(chan, "vm-youhave");
08606 if (!res) {
08607 if (vms->newmessages) {
08608 if ((vms->newmessages == 1))
08609 res = ast_play_and_wait(chan, "digits/1F");
08610 else
08611 res = say_and_wait(chan, vms->newmessages, chan->language);
08612 if (!res)
08613 res = ast_play_and_wait(chan, "vm-INBOX");
08614 if (vms->oldmessages && !res)
08615 res = ast_play_and_wait(chan, "vm-and");
08616 else if (!res) {
08617 if ((vms->newmessages == 1))
08618 res = ast_play_and_wait(chan, "vm-message");
08619 else
08620 res = ast_play_and_wait(chan, "vm-messages");
08621 }
08622
08623 }
08624 if (!res && vms->oldmessages) {
08625 if (vms->oldmessages == 1)
08626 res = ast_play_and_wait(chan, "digits/1F");
08627 else
08628 res = say_and_wait(chan, vms->oldmessages, chan->language);
08629 if (!res)
08630 res = ast_play_and_wait(chan, "vm-Old");
08631 if (!res) {
08632 if (vms->oldmessages == 1)
08633 res = ast_play_and_wait(chan, "vm-message");
08634 else
08635 res = ast_play_and_wait(chan, "vm-messages");
08636 }
08637 }
08638 if (!res) {
08639 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08640 res = ast_play_and_wait(chan, "vm-no");
08641 if (!res)
08642 res = ast_play_and_wait(chan, "vm-messages");
08643 }
08644 }
08645 }
08646 return res;
08647 }
08648
08649
08650 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08651 {
08652
08653 int res;
08654 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08655 res = ast_play_and_wait(chan, "vm-youhaveno");
08656 if (!res)
08657 res = ast_play_and_wait(chan, "vm-messages");
08658 } else {
08659 res = ast_play_and_wait(chan, "vm-youhave");
08660 }
08661 if (!res) {
08662 if (vms->newmessages) {
08663 if (!res) {
08664 if ((vms->newmessages == 1)) {
08665 res = ast_play_and_wait(chan, "digits/1M");
08666 if (!res)
08667 res = ast_play_and_wait(chan, "vm-message");
08668 if (!res)
08669 res = ast_play_and_wait(chan, "vm-INBOXs");
08670 } else {
08671 res = say_and_wait(chan, vms->newmessages, chan->language);
08672 if (!res)
08673 res = ast_play_and_wait(chan, "vm-messages");
08674 if (!res)
08675 res = ast_play_and_wait(chan, "vm-INBOX");
08676 }
08677 }
08678 if (vms->oldmessages && !res)
08679 res = ast_play_and_wait(chan, "vm-and");
08680 }
08681 if (vms->oldmessages) {
08682 if (!res) {
08683 if (vms->oldmessages == 1) {
08684 res = ast_play_and_wait(chan, "digits/1M");
08685 if (!res)
08686 res = ast_play_and_wait(chan, "vm-message");
08687 if (!res)
08688 res = ast_play_and_wait(chan, "vm-Olds");
08689 } else {
08690 res = say_and_wait(chan, vms->oldmessages, chan->language);
08691 if (!res)
08692 res = ast_play_and_wait(chan, "vm-messages");
08693 if (!res)
08694 res = ast_play_and_wait(chan, "vm-Old");
08695 }
08696 }
08697 }
08698 }
08699 return res;
08700 }
08701
08702
08703 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08704
08705 int res;
08706 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08707 res = ast_play_and_wait(chan, "vm-nomessages");
08708 return res;
08709 } else {
08710 res = ast_play_and_wait(chan, "vm-youhave");
08711 }
08712 if (vms->newmessages) {
08713 if (!res)
08714 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08715 if ((vms->newmessages == 1)) {
08716 if (!res)
08717 res = ast_play_and_wait(chan, "vm-message");
08718 if (!res)
08719 res = ast_play_and_wait(chan, "vm-INBOXs");
08720 } else {
08721 if (!res)
08722 res = ast_play_and_wait(chan, "vm-messages");
08723 if (!res)
08724 res = ast_play_and_wait(chan, "vm-INBOX");
08725 }
08726 if (vms->oldmessages && !res)
08727 res = ast_play_and_wait(chan, "vm-and");
08728 }
08729 if (vms->oldmessages) {
08730 if (!res)
08731 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08732 if (vms->oldmessages == 1) {
08733 if (!res)
08734 res = ast_play_and_wait(chan, "vm-message");
08735 if (!res)
08736 res = ast_play_and_wait(chan, "vm-Olds");
08737 } else {
08738 if (!res)
08739 res = ast_play_and_wait(chan, "vm-messages");
08740 if (!res)
08741 res = ast_play_and_wait(chan, "vm-Old");
08742 }
08743 }
08744 return res;
08745 }
08746
08747
08748 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08749 {
08750
08751 int res;
08752 res = ast_play_and_wait(chan, "vm-youhave");
08753 if (!res) {
08754 if (vms->newmessages) {
08755 res = say_and_wait(chan, vms->newmessages, chan->language);
08756 if (!res)
08757 res = ast_play_and_wait(chan, "vm-INBOX");
08758 if (vms->oldmessages && !res)
08759 res = ast_play_and_wait(chan, "vm-and");
08760 else if (!res) {
08761 if ((vms->newmessages == 1))
08762 res = ast_play_and_wait(chan, "vm-message");
08763 else
08764 res = ast_play_and_wait(chan, "vm-messages");
08765 }
08766
08767 }
08768 if (!res && vms->oldmessages) {
08769 res = say_and_wait(chan, vms->oldmessages, chan->language);
08770 if (!res)
08771 res = ast_play_and_wait(chan, "vm-Old");
08772 if (!res) {
08773 if (vms->oldmessages == 1)
08774 res = ast_play_and_wait(chan, "vm-message");
08775 else
08776 res = ast_play_and_wait(chan, "vm-messages");
08777 }
08778 }
08779 if (!res) {
08780 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08781 res = ast_play_and_wait(chan, "vm-no");
08782 if (!res)
08783 res = ast_play_and_wait(chan, "vm-messages");
08784 }
08785 }
08786 }
08787 return res;
08788 }
08789
08790
08791 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08792 {
08793
08794 int res;
08795 res = ast_play_and_wait(chan, "vm-youhave");
08796 if (!res) {
08797 if (vms->newmessages) {
08798 res = say_and_wait(chan, vms->newmessages, chan->language);
08799 if (!res) {
08800 if (vms->newmessages == 1)
08801 res = ast_play_and_wait(chan, "vm-INBOXs");
08802 else
08803 res = ast_play_and_wait(chan, "vm-INBOX");
08804 }
08805 if (vms->oldmessages && !res)
08806 res = ast_play_and_wait(chan, "vm-and");
08807 else if (!res) {
08808 if ((vms->newmessages == 1))
08809 res = ast_play_and_wait(chan, "vm-message");
08810 else
08811 res = ast_play_and_wait(chan, "vm-messages");
08812 }
08813
08814 }
08815 if (!res && vms->oldmessages) {
08816 res = say_and_wait(chan, vms->oldmessages, chan->language);
08817 if (!res) {
08818 if (vms->oldmessages == 1)
08819 res = ast_play_and_wait(chan, "vm-Olds");
08820 else
08821 res = ast_play_and_wait(chan, "vm-Old");
08822 }
08823 if (!res) {
08824 if (vms->oldmessages == 1)
08825 res = ast_play_and_wait(chan, "vm-message");
08826 else
08827 res = ast_play_and_wait(chan, "vm-messages");
08828 }
08829 }
08830 if (!res) {
08831 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08832 res = ast_play_and_wait(chan, "vm-no");
08833 if (!res)
08834 res = ast_play_and_wait(chan, "vm-messages");
08835 }
08836 }
08837 }
08838 return res;
08839 }
08840
08841
08842 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08843 {
08844
08845 int res;
08846 res = ast_play_and_wait(chan, "vm-youhave");
08847 if (!res) {
08848 if (vms->newmessages) {
08849 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08850 if (!res) {
08851 if ((vms->newmessages == 1)) {
08852 res = ast_play_and_wait(chan, "vm-message");
08853 if (!res)
08854 res = ast_play_and_wait(chan, "vm-INBOXs");
08855 } else {
08856 res = ast_play_and_wait(chan, "vm-messages");
08857 if (!res)
08858 res = ast_play_and_wait(chan, "vm-INBOX");
08859 }
08860 }
08861 if (vms->oldmessages && !res)
08862 res = ast_play_and_wait(chan, "vm-and");
08863 }
08864 if (!res && vms->oldmessages) {
08865 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08866 if (!res) {
08867 if (vms->oldmessages == 1) {
08868 res = ast_play_and_wait(chan, "vm-message");
08869 if (!res)
08870 res = ast_play_and_wait(chan, "vm-Olds");
08871 } else {
08872 res = ast_play_and_wait(chan, "vm-messages");
08873 if (!res)
08874 res = ast_play_and_wait(chan, "vm-Old");
08875 }
08876 }
08877 }
08878 if (!res) {
08879 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08880 res = ast_play_and_wait(chan, "vm-no");
08881 if (!res)
08882 res = ast_play_and_wait(chan, "vm-messages");
08883 }
08884 }
08885 }
08886 return res;
08887 }
08888
08889
08890
08891
08892
08893
08894
08895
08896
08897
08898
08899
08900
08901
08902
08903
08904
08905 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08906 {
08907 int res;
08908 res = ast_play_and_wait(chan, "vm-youhave");
08909 if (!res) {
08910 if (vms->newmessages) {
08911 if (vms->newmessages == 1) {
08912 res = ast_play_and_wait(chan, "digits/jednu");
08913 } else {
08914 res = say_and_wait(chan, vms->newmessages, chan->language);
08915 }
08916 if (!res) {
08917 if ((vms->newmessages == 1))
08918 res = ast_play_and_wait(chan, "vm-novou");
08919 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08920 res = ast_play_and_wait(chan, "vm-nove");
08921 if (vms->newmessages > 4)
08922 res = ast_play_and_wait(chan, "vm-novych");
08923 }
08924 if (vms->oldmessages && !res)
08925 res = ast_play_and_wait(chan, "vm-and");
08926 else if (!res) {
08927 if ((vms->newmessages == 1))
08928 res = ast_play_and_wait(chan, "vm-zpravu");
08929 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08930 res = ast_play_and_wait(chan, "vm-zpravy");
08931 if (vms->newmessages > 4)
08932 res = ast_play_and_wait(chan, "vm-zprav");
08933 }
08934 }
08935 if (!res && vms->oldmessages) {
08936 res = say_and_wait(chan, vms->oldmessages, chan->language);
08937 if (!res) {
08938 if ((vms->oldmessages == 1))
08939 res = ast_play_and_wait(chan, "vm-starou");
08940 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08941 res = ast_play_and_wait(chan, "vm-stare");
08942 if (vms->oldmessages > 4)
08943 res = ast_play_and_wait(chan, "vm-starych");
08944 }
08945 if (!res) {
08946 if ((vms->oldmessages == 1))
08947 res = ast_play_and_wait(chan, "vm-zpravu");
08948 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08949 res = ast_play_and_wait(chan, "vm-zpravy");
08950 if (vms->oldmessages > 4)
08951 res = ast_play_and_wait(chan, "vm-zprav");
08952 }
08953 }
08954 if (!res) {
08955 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08956 res = ast_play_and_wait(chan, "vm-no");
08957 if (!res)
08958 res = ast_play_and_wait(chan, "vm-zpravy");
08959 }
08960 }
08961 }
08962 return res;
08963 }
08964
08965
08966 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08967 {
08968 int res;
08969
08970 res = ast_play_and_wait(chan, "vm-you");
08971
08972 if (!res && vms->newmessages) {
08973 res = ast_play_and_wait(chan, "vm-have");
08974 if (!res)
08975 res = say_and_wait(chan, vms->newmessages, chan->language);
08976 if (!res)
08977 res = ast_play_and_wait(chan, "vm-tong");
08978 if (!res)
08979 res = ast_play_and_wait(chan, "vm-INBOX");
08980 if (vms->oldmessages && !res)
08981 res = ast_play_and_wait(chan, "vm-and");
08982 else if (!res)
08983 res = ast_play_and_wait(chan, "vm-messages");
08984 }
08985 if (!res && vms->oldmessages) {
08986 res = ast_play_and_wait(chan, "vm-have");
08987 if (!res)
08988 res = say_and_wait(chan, vms->oldmessages, chan->language);
08989 if (!res)
08990 res = ast_play_and_wait(chan, "vm-tong");
08991 if (!res)
08992 res = ast_play_and_wait(chan, "vm-Old");
08993 if (!res)
08994 res = ast_play_and_wait(chan, "vm-messages");
08995 }
08996 if (!res && !vms->oldmessages && !vms->newmessages) {
08997 res = ast_play_and_wait(chan, "vm-haveno");
08998 if (!res)
08999 res = ast_play_and_wait(chan, "vm-messages");
09000 }
09001 return res;
09002 }
09003
09004
09005 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09006 {
09007 int res;
09008
09009
09010 res = ast_play_and_wait(chan, "vm-youhave");
09011 if (!res) {
09012 if (vms->newmessages) {
09013 res = say_and_wait(chan, vms->newmessages, chan->language);
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 }
09019 if (!res && vms->oldmessages) {
09020 res = say_and_wait(chan, vms->oldmessages, chan->language);
09021 if (!res)
09022 res = ast_play_and_wait(chan, "vm-Old");
09023 }
09024 if (!res) {
09025 if (!vms->oldmessages && !vms->newmessages) {
09026 res = ast_play_and_wait(chan, "vm-no");
09027 if (!res)
09028 res = ast_play_and_wait(chan, "vm-message");
09029 }
09030 }
09031 }
09032 return res;
09033 }
09034
09035 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09036 {
09037 char prefile[256];
09038
09039
09040 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09041 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09042 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09043 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09044 ast_play_and_wait(chan, "vm-tempgreetactive");
09045 }
09046 DISPOSE(prefile, -1);
09047 }
09048
09049
09050 if (0) {
09051 return 0;
09052 } else if (!strncasecmp(chan->language, "cs", 2)) {
09053 return vm_intro_cs(chan, vms);
09054 } else if (!strncasecmp(chan->language, "cz", 2)) {
09055 static int deprecation_warning = 0;
09056 if (deprecation_warning++ % 10 == 0) {
09057 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09058 }
09059 return vm_intro_cs(chan, vms);
09060 } else if (!strncasecmp(chan->language, "de", 2)) {
09061 return vm_intro_de(chan, vms);
09062 } else if (!strncasecmp(chan->language, "es", 2)) {
09063 return vm_intro_es(chan, vms);
09064 } else if (!strncasecmp(chan->language, "fr", 2)) {
09065 return vm_intro_fr(chan, vms);
09066 } else if (!strncasecmp(chan->language, "gr", 2)) {
09067 return vm_intro_gr(chan, vms);
09068 } else if (!strncasecmp(chan->language, "he", 2)) {
09069 return vm_intro_he(chan, vms);
09070 } else if (!strncasecmp(chan->language, "it", 2)) {
09071 return vm_intro_it(chan, vms);
09072 } else if (!strncasecmp(chan->language, "nl", 2)) {
09073 return vm_intro_nl(chan, vms);
09074 } else if (!strncasecmp(chan->language, "no", 2)) {
09075 return vm_intro_no(chan, vms);
09076 } else if (!strncasecmp(chan->language, "pl", 2)) {
09077 return vm_intro_pl(chan, vms);
09078 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09079 return vm_intro_pt_BR(chan, vms);
09080 } else if (!strncasecmp(chan->language, "pt", 2)) {
09081 return vm_intro_pt(chan, vms);
09082 } else if (!strncasecmp(chan->language, "ru", 2)) {
09083 return vm_intro_multilang(chan, vms, "n");
09084 } else if (!strncasecmp(chan->language, "se", 2)) {
09085 return vm_intro_se(chan, vms);
09086 } else if (!strncasecmp(chan->language, "ua", 2)) {
09087 return vm_intro_multilang(chan, vms, "n");
09088 } else if (!strncasecmp(chan->language, "vi", 2)) {
09089 return vm_intro_vi(chan, vms);
09090 } else if (!strncasecmp(chan->language, "zh", 2)) {
09091 return vm_intro_zh(chan, vms);
09092 } else {
09093 return vm_intro_en(chan, vms);
09094 }
09095 }
09096
09097 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09098 {
09099 int res = 0;
09100
09101 while (!res) {
09102 if (vms->starting) {
09103 if (vms->lastmsg > -1) {
09104 if (skipadvanced)
09105 res = ast_play_and_wait(chan, "vm-onefor-full");
09106 else
09107 res = ast_play_and_wait(chan, "vm-onefor");
09108 if (!res)
09109 res = vm_play_folder_name(chan, vms->vmbox);
09110 }
09111 if (!res) {
09112 if (skipadvanced)
09113 res = ast_play_and_wait(chan, "vm-opts-full");
09114 else
09115 res = ast_play_and_wait(chan, "vm-opts");
09116 }
09117 } else {
09118
09119 if (skipadvanced) {
09120 res = ast_play_and_wait(chan, "vm-onefor-full");
09121 if (!res)
09122 res = vm_play_folder_name(chan, vms->vmbox);
09123 res = ast_play_and_wait(chan, "vm-opts-full");
09124 }
09125
09126
09127
09128
09129
09130
09131 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09132 res = ast_play_and_wait(chan, "vm-prev");
09133 }
09134 if (!res && !skipadvanced)
09135 res = ast_play_and_wait(chan, "vm-advopts");
09136 if (!res)
09137 res = ast_play_and_wait(chan, "vm-repeat");
09138
09139
09140
09141
09142
09143
09144 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09145 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09146 res = ast_play_and_wait(chan, "vm-next");
09147 }
09148 if (!res) {
09149 int curmsg_deleted;
09150 #ifdef IMAP_STORAGE
09151 ast_mutex_lock(&vms->lock);
09152 #endif
09153 curmsg_deleted = vms->deleted[vms->curmsg];
09154 #ifdef IMAP_STORAGE
09155 ast_mutex_unlock(&vms->lock);
09156 #endif
09157 if (!curmsg_deleted) {
09158 res = ast_play_and_wait(chan, "vm-delete");
09159 } else {
09160 res = ast_play_and_wait(chan, "vm-undelete");
09161 }
09162 if (!res) {
09163 res = ast_play_and_wait(chan, "vm-toforward");
09164 }
09165 if (!res) {
09166 res = ast_play_and_wait(chan, "vm-savemessage");
09167 }
09168 }
09169 }
09170 if (!res) {
09171 res = ast_play_and_wait(chan, "vm-helpexit");
09172 }
09173 if (!res)
09174 res = ast_waitfordigit(chan, 6000);
09175 if (!res) {
09176 vms->repeats++;
09177 if (vms->repeats > 2) {
09178 res = 't';
09179 }
09180 }
09181 }
09182 return res;
09183 }
09184
09185 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09186 {
09187 int res = 0;
09188
09189 while (!res) {
09190 if (vms->lastmsg > -1) {
09191 res = ast_play_and_wait(chan, "vm-listen");
09192 if (!res)
09193 res = vm_play_folder_name(chan, vms->vmbox);
09194 if (!res)
09195 res = ast_play_and_wait(chan, "press");
09196 if (!res)
09197 res = ast_play_and_wait(chan, "digits/1");
09198 }
09199 if (!res)
09200 res = ast_play_and_wait(chan, "vm-opts");
09201 if (!res) {
09202 vms->starting = 0;
09203 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09204 }
09205 }
09206 return res;
09207 }
09208
09209 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09210 {
09211 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09212 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09213 } else {
09214 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09215 }
09216 }
09217
09218
09219 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09220 {
09221 int cmd = 0;
09222 int duration = 0;
09223 int tries = 0;
09224 char newpassword[80] = "";
09225 char newpassword2[80] = "";
09226 char prefile[PATH_MAX] = "";
09227 unsigned char buf[256];
09228 int bytes = 0;
09229
09230 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09231 if (ast_adsi_available(chan)) {
09232 bytes += adsi_logo(buf + bytes);
09233 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09234 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09235 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09236 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09237 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09238 }
09239
09240
09241 if (ast_test_flag(vmu, VM_FORCENAME)) {
09242 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09243 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09244 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09245 if (cmd < 0 || cmd == 't' || cmd == '#')
09246 return cmd;
09247 }
09248 }
09249
09250
09251 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09252 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09253 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09254 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09255 if (cmd < 0 || cmd == 't' || cmd == '#')
09256 return cmd;
09257 }
09258
09259 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09260 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09261 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09262 if (cmd < 0 || cmd == 't' || cmd == '#')
09263 return cmd;
09264 }
09265 }
09266
09267
09268
09269
09270
09271 for (;;) {
09272 newpassword[1] = '\0';
09273 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09274 if (cmd == '#')
09275 newpassword[0] = '\0';
09276 if (cmd < 0 || cmd == 't' || cmd == '#')
09277 return cmd;
09278 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09279 if (cmd < 0 || cmd == 't' || cmd == '#')
09280 return cmd;
09281 cmd = check_password(vmu, newpassword);
09282 if (cmd != 0) {
09283 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09284 cmd = ast_play_and_wait(chan, vm_invalid_password);
09285 } else {
09286 newpassword2[1] = '\0';
09287 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09288 if (cmd == '#')
09289 newpassword2[0] = '\0';
09290 if (cmd < 0 || cmd == 't' || cmd == '#')
09291 return cmd;
09292 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09293 if (cmd < 0 || cmd == 't' || cmd == '#')
09294 return cmd;
09295 if (!strcmp(newpassword, newpassword2))
09296 break;
09297 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09298 cmd = ast_play_and_wait(chan, vm_mismatch);
09299 }
09300 if (++tries == 3)
09301 return -1;
09302 if (cmd != 0) {
09303 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09304 }
09305 }
09306 if (pwdchange & PWDCHANGE_INTERNAL)
09307 vm_change_password(vmu, newpassword);
09308 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09309 vm_change_password_shell(vmu, newpassword);
09310
09311 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09312 cmd = ast_play_and_wait(chan, vm_passchanged);
09313
09314 return cmd;
09315 }
09316
09317 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09318 {
09319 int cmd = 0;
09320 int retries = 0;
09321 int duration = 0;
09322 char newpassword[80] = "";
09323 char newpassword2[80] = "";
09324 char prefile[PATH_MAX] = "";
09325 unsigned char buf[256];
09326 int bytes = 0;
09327
09328 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09329 if (ast_adsi_available(chan)) {
09330 bytes += adsi_logo(buf + bytes);
09331 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09332 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09333 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09334 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09335 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09336 }
09337 while ((cmd >= 0) && (cmd != 't')) {
09338 if (cmd)
09339 retries = 0;
09340 switch (cmd) {
09341 case '1':
09342 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09343 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09344 break;
09345 case '2':
09346 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09347 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09348 break;
09349 case '3':
09350 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09351 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09352 break;
09353 case '4':
09354 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09355 break;
09356 case '5':
09357 if (vmu->password[0] == '-') {
09358 cmd = ast_play_and_wait(chan, "vm-no");
09359 break;
09360 }
09361 newpassword[1] = '\0';
09362 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09363 if (cmd == '#')
09364 newpassword[0] = '\0';
09365 else {
09366 if (cmd < 0)
09367 break;
09368 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09369 break;
09370 }
09371 }
09372 cmd = check_password(vmu, newpassword);
09373 if (cmd != 0) {
09374 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09375 cmd = ast_play_and_wait(chan, vm_invalid_password);
09376 if (!cmd) {
09377 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09378 }
09379 break;
09380 }
09381 newpassword2[1] = '\0';
09382 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09383 if (cmd == '#')
09384 newpassword2[0] = '\0';
09385 else {
09386 if (cmd < 0)
09387 break;
09388
09389 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09390 break;
09391 }
09392 }
09393 if (strcmp(newpassword, newpassword2)) {
09394 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09395 cmd = ast_play_and_wait(chan, vm_mismatch);
09396 if (!cmd) {
09397 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09398 }
09399 break;
09400 }
09401
09402 if (pwdchange & PWDCHANGE_INTERNAL) {
09403 vm_change_password(vmu, newpassword);
09404 }
09405 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09406 vm_change_password_shell(vmu, newpassword);
09407 }
09408
09409 ast_debug(1, "User %s set password to %s of length %d\n",
09410 vms->username, newpassword, (int) strlen(newpassword));
09411 cmd = ast_play_and_wait(chan, vm_passchanged);
09412 break;
09413 case '*':
09414 cmd = 't';
09415 break;
09416 default:
09417 cmd = 0;
09418 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09419 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09420 if (ast_fileexists(prefile, NULL, NULL)) {
09421 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09422 }
09423 DISPOSE(prefile, -1);
09424 if (!cmd) {
09425 cmd = ast_play_and_wait(chan, "vm-options");
09426 }
09427 if (!cmd) {
09428 cmd = ast_waitfordigit(chan, 6000);
09429 }
09430 if (!cmd) {
09431 retries++;
09432 }
09433 if (retries > 3) {
09434 cmd = 't';
09435 }
09436 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09437 }
09438 }
09439 if (cmd == 't')
09440 cmd = 0;
09441 return cmd;
09442 }
09443
09444
09445
09446
09447
09448
09449
09450
09451
09452
09453
09454
09455
09456
09457
09458
09459
09460 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09461 {
09462 int cmd = 0;
09463 int retries = 0;
09464 int duration = 0;
09465 char prefile[PATH_MAX] = "";
09466 unsigned char buf[256];
09467 int bytes = 0;
09468
09469 if (ast_adsi_available(chan)) {
09470 bytes += adsi_logo(buf + bytes);
09471 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09472 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09473 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09474 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09475 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09476 }
09477
09478 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09479 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09480 while ((cmd >= 0) && (cmd != 't')) {
09481 if (cmd)
09482 retries = 0;
09483 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09484 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09485 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09486 if (cmd == -1) {
09487 break;
09488 }
09489 cmd = 't';
09490 } else {
09491 switch (cmd) {
09492 case '1':
09493 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09494 break;
09495 case '2':
09496 DELETE(prefile, -1, prefile, vmu);
09497 ast_play_and_wait(chan, "vm-tempremoved");
09498 cmd = 't';
09499 break;
09500 case '*':
09501 cmd = 't';
09502 break;
09503 default:
09504 cmd = ast_play_and_wait(chan,
09505 ast_fileexists(prefile, NULL, NULL) > 0 ?
09506 "vm-tempgreeting2" : "vm-tempgreeting");
09507 if (!cmd) {
09508 cmd = ast_waitfordigit(chan, 6000);
09509 }
09510 if (!cmd) {
09511 retries++;
09512 }
09513 if (retries > 3) {
09514 cmd = 't';
09515 }
09516 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09517 }
09518 }
09519 DISPOSE(prefile, -1);
09520 }
09521 if (cmd == 't')
09522 cmd = 0;
09523 return cmd;
09524 }
09525
09526
09527
09528
09529
09530
09531
09532
09533
09534 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09535 {
09536 int cmd = 0;
09537
09538 if (vms->lastmsg > -1) {
09539 cmd = play_message(chan, vmu, vms);
09540 } else {
09541 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09542 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09543 if (!cmd) {
09544 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09545 cmd = ast_play_and_wait(chan, vms->fn);
09546 }
09547 if (!cmd)
09548 cmd = ast_play_and_wait(chan, "vm-messages");
09549 } else {
09550 if (!cmd)
09551 cmd = ast_play_and_wait(chan, "vm-messages");
09552 if (!cmd) {
09553 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09554 cmd = ast_play_and_wait(chan, vms->fn);
09555 }
09556 }
09557 }
09558 return cmd;
09559 }
09560
09561
09562 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09563 {
09564 int cmd = 0;
09565
09566 if (vms->lastmsg > -1) {
09567 cmd = play_message(chan, vmu, vms);
09568 } else {
09569 if (!strcasecmp(vms->fn, "INBOX")) {
09570 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09571 } else {
09572 cmd = ast_play_and_wait(chan, "vm-nomessages");
09573 }
09574 }
09575 return cmd;
09576 }
09577
09578
09579
09580
09581
09582
09583
09584
09585
09586 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09587 {
09588 int cmd = 0;
09589
09590 if (vms->lastmsg > -1) {
09591 cmd = play_message(chan, vmu, vms);
09592 } else {
09593 cmd = ast_play_and_wait(chan, "vm-youhave");
09594 if (!cmd)
09595 cmd = ast_play_and_wait(chan, "vm-no");
09596 if (!cmd) {
09597 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09598 cmd = ast_play_and_wait(chan, vms->fn);
09599 }
09600 if (!cmd)
09601 cmd = ast_play_and_wait(chan, "vm-messages");
09602 }
09603 return cmd;
09604 }
09605
09606
09607
09608
09609
09610
09611
09612
09613
09614 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09615 {
09616 int cmd;
09617
09618 if (vms->lastmsg > -1) {
09619 cmd = play_message(chan, vmu, vms);
09620 } else {
09621 cmd = ast_play_and_wait(chan, "vm-no");
09622 if (!cmd)
09623 cmd = ast_play_and_wait(chan, "vm-message");
09624 if (!cmd) {
09625 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09626 cmd = ast_play_and_wait(chan, vms->fn);
09627 }
09628 }
09629 return cmd;
09630 }
09631
09632
09633
09634
09635
09636
09637
09638
09639
09640 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09641 {
09642 int cmd;
09643
09644 if (vms->lastmsg > -1) {
09645 cmd = play_message(chan, vmu, vms);
09646 } else {
09647 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09648 if (!cmd)
09649 cmd = ast_play_and_wait(chan, "vm-messages");
09650 if (!cmd) {
09651 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09652 cmd = ast_play_and_wait(chan, vms->fn);
09653 }
09654 }
09655 return cmd;
09656 }
09657
09658
09659
09660
09661
09662
09663
09664
09665
09666 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09667 {
09668 int cmd;
09669
09670 if (vms->lastmsg > -1) {
09671 cmd = play_message(chan, vmu, vms);
09672 } else {
09673 cmd = ast_play_and_wait(chan, "vm-no");
09674 if (!cmd) {
09675 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09676 cmd = ast_play_and_wait(chan, vms->fn);
09677 }
09678 if (!cmd)
09679 cmd = ast_play_and_wait(chan, "vm-messages");
09680 }
09681 return cmd;
09682 }
09683
09684
09685
09686
09687
09688
09689
09690
09691
09692 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09693 {
09694 int cmd;
09695
09696 if (vms->lastmsg > -1) {
09697 cmd = play_message(chan, vmu, vms);
09698 } else {
09699 cmd = ast_play_and_wait(chan, "vm-you");
09700 if (!cmd)
09701 cmd = ast_play_and_wait(chan, "vm-haveno");
09702 if (!cmd)
09703 cmd = ast_play_and_wait(chan, "vm-messages");
09704 if (!cmd) {
09705 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09706 cmd = ast_play_and_wait(chan, vms->fn);
09707 }
09708 }
09709 return cmd;
09710 }
09711
09712
09713
09714
09715
09716
09717
09718
09719
09720 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09721 {
09722 int cmd = 0;
09723
09724 if (vms->lastmsg > -1) {
09725 cmd = play_message(chan, vmu, vms);
09726 } else {
09727 cmd = ast_play_and_wait(chan, "vm-no");
09728 if (!cmd) {
09729 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09730 cmd = ast_play_and_wait(chan, vms->fn);
09731 }
09732 }
09733 return cmd;
09734 }
09735
09736
09737
09738
09739
09740
09741
09742
09743
09744
09745
09746
09747 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09748 {
09749 if (!strncasecmp(chan->language, "es", 2)) {
09750 return vm_browse_messages_es(chan, vms, vmu);
09751 } else if (!strncasecmp(chan->language, "gr", 2)) {
09752 return vm_browse_messages_gr(chan, vms, vmu);
09753 } else if (!strncasecmp(chan->language, "he", 2)) {
09754 return vm_browse_messages_he(chan, vms, vmu);
09755 } else if (!strncasecmp(chan->language, "it", 2)) {
09756 return vm_browse_messages_it(chan, vms, vmu);
09757 } else if (!strncasecmp(chan->language, "pt", 2)) {
09758 return vm_browse_messages_pt(chan, vms, vmu);
09759 } else if (!strncasecmp(chan->language, "vi", 2)) {
09760 return vm_browse_messages_vi(chan, vms, vmu);
09761 } else if (!strncasecmp(chan->language, "zh", 2)) {
09762 return vm_browse_messages_zh(chan, vms, vmu);
09763 } else {
09764 return vm_browse_messages_en(chan, vms, vmu);
09765 }
09766 }
09767
09768 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09769 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09770 int skipuser, int max_logins, int silent)
09771 {
09772 int useadsi = 0, valid = 0, logretries = 0;
09773 char password[AST_MAX_EXTENSION]="", *passptr;
09774 struct ast_vm_user vmus, *vmu = NULL;
09775
09776
09777 adsi_begin(chan, &useadsi);
09778 if (!skipuser && useadsi)
09779 adsi_login(chan);
09780 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09781 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09782 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09783 return -1;
09784 }
09785
09786
09787
09788 while (!valid && (logretries < max_logins)) {
09789
09790 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09791 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09792 return -1;
09793 }
09794 if (ast_strlen_zero(mailbox)) {
09795 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09796 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09797 } else {
09798 ast_verb(3, "Username not entered\n");
09799 return -1;
09800 }
09801 } else if (mailbox[0] == '*') {
09802
09803 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09804 if (ast_exists_extension(chan, chan->context, "a", 1,
09805 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09806 return -1;
09807 }
09808 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09809 mailbox[0] = '\0';
09810 }
09811
09812 if (useadsi)
09813 adsi_password(chan);
09814
09815 if (!ast_strlen_zero(prefix)) {
09816 char fullusername[80] = "";
09817 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09818 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09819 ast_copy_string(mailbox, fullusername, mailbox_size);
09820 }
09821
09822 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09823 vmu = find_user(&vmus, context, mailbox);
09824 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09825
09826 password[0] = '\0';
09827 } else {
09828 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09829 if (ast_streamfile(chan, vm_password, chan->language)) {
09830 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09831 return -1;
09832 }
09833 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09834 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09835 return -1;
09836 } else if (password[0] == '*') {
09837
09838 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09839 if (ast_exists_extension(chan, chan->context, "a", 1,
09840 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09841 mailbox[0] = '*';
09842 return -1;
09843 }
09844 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09845 mailbox[0] = '\0';
09846
09847 vmu = NULL;
09848 }
09849 }
09850
09851 if (vmu) {
09852 passptr = vmu->password;
09853 if (passptr[0] == '-') passptr++;
09854 }
09855 if (vmu && !strcmp(passptr, password))
09856 valid++;
09857 else {
09858 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09859 if (!ast_strlen_zero(prefix))
09860 mailbox[0] = '\0';
09861 }
09862 logretries++;
09863 if (!valid) {
09864 if (skipuser || logretries >= max_logins) {
09865 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09866 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09867 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09868 return -1;
09869 }
09870 } else {
09871 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09872 if (useadsi)
09873 adsi_login(chan);
09874 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09875 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09876 return -1;
09877 }
09878 }
09879 if (ast_waitstream(chan, ""))
09880 return -1;
09881 }
09882 }
09883 if (!valid && (logretries >= max_logins)) {
09884 ast_stopstream(chan);
09885 ast_play_and_wait(chan, "vm-goodbye");
09886 return -1;
09887 }
09888 if (vmu && !skipuser) {
09889 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09890 }
09891 return 0;
09892 }
09893
09894 static int vm_execmain(struct ast_channel *chan, const char *data)
09895 {
09896
09897
09898
09899 int res = -1;
09900 int cmd = 0;
09901 int valid = 0;
09902 char prefixstr[80] ="";
09903 char ext_context[256]="";
09904 int box;
09905 int useadsi = 0;
09906 int skipuser = 0;
09907 struct vm_state vms;
09908 struct ast_vm_user *vmu = NULL, vmus;
09909 char *context = NULL;
09910 int silentexit = 0;
09911 struct ast_flags flags = { 0 };
09912 signed char record_gain = 0;
09913 int play_auto = 0;
09914 int play_folder = 0;
09915 int in_urgent = 0;
09916 #ifdef IMAP_STORAGE
09917 int deleted = 0;
09918 #endif
09919
09920
09921 memset(&vms, 0, sizeof(vms));
09922
09923 vms.lastmsg = -1;
09924
09925 memset(&vmus, 0, sizeof(vmus));
09926
09927 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09928 if (chan->_state != AST_STATE_UP) {
09929 ast_debug(1, "Before ast_answer\n");
09930 ast_answer(chan);
09931 }
09932
09933 if (!ast_strlen_zero(data)) {
09934 char *opts[OPT_ARG_ARRAY_SIZE];
09935 char *parse;
09936 AST_DECLARE_APP_ARGS(args,
09937 AST_APP_ARG(argv0);
09938 AST_APP_ARG(argv1);
09939 );
09940
09941 parse = ast_strdupa(data);
09942
09943 AST_STANDARD_APP_ARGS(args, parse);
09944
09945 if (args.argc == 2) {
09946 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09947 return -1;
09948 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09949 int gain;
09950 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09951 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09952 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09953 return -1;
09954 } else {
09955 record_gain = (signed char) gain;
09956 }
09957 } else {
09958 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09959 }
09960 }
09961 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09962 play_auto = 1;
09963 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09964
09965 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09966 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09967 play_folder = -1;
09968 }
09969 } else {
09970 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09971 }
09972 } else {
09973 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09974 }
09975 if (play_folder > 9 || play_folder < 0) {
09976 ast_log(AST_LOG_WARNING,
09977 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09978 opts[OPT_ARG_PLAYFOLDER]);
09979 play_folder = 0;
09980 }
09981 }
09982 } else {
09983
09984 while (*(args.argv0)) {
09985 if (*(args.argv0) == 's')
09986 ast_set_flag(&flags, OPT_SILENT);
09987 else if (*(args.argv0) == 'p')
09988 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09989 else
09990 break;
09991 (args.argv0)++;
09992 }
09993
09994 }
09995
09996 valid = ast_test_flag(&flags, OPT_SILENT);
09997
09998 if ((context = strchr(args.argv0, '@')))
09999 *context++ = '\0';
10000
10001 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10002 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10003 else
10004 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10005
10006 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10007 skipuser++;
10008 else
10009 valid = 0;
10010 }
10011
10012 if (!valid)
10013 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10014
10015 ast_debug(1, "After vm_authenticate\n");
10016
10017 if (vms.username[0] == '*') {
10018 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10019
10020
10021 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10022 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10023 res = 0;
10024 goto out;
10025 }
10026 }
10027
10028 if (!res) {
10029 valid = 1;
10030 if (!skipuser)
10031 vmu = &vmus;
10032 } else {
10033 res = 0;
10034 }
10035
10036
10037 adsi_begin(chan, &useadsi);
10038
10039 ast_test_suite_assert(valid);
10040 if (!valid) {
10041 goto out;
10042 }
10043 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10044
10045 #ifdef IMAP_STORAGE
10046 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10047 pthread_setspecific(ts_vmstate.key, &vms);
10048
10049 vms.interactive = 1;
10050 vms.updated = 1;
10051 if (vmu)
10052 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10053 vmstate_insert(&vms);
10054 init_vm_state(&vms);
10055 #endif
10056
10057
10058 if (!ast_strlen_zero(vmu->language))
10059 ast_string_field_set(chan, language, vmu->language);
10060
10061
10062 ast_debug(1, "Before open_mailbox\n");
10063 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10064 if (res < 0)
10065 goto out;
10066 vms.oldmessages = vms.lastmsg + 1;
10067 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10068
10069 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10070 if (res < 0)
10071 goto out;
10072 vms.newmessages = vms.lastmsg + 1;
10073 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10074
10075 in_urgent = 1;
10076 res = open_mailbox(&vms, vmu, 11);
10077 if (res < 0)
10078 goto out;
10079 vms.urgentmessages = vms.lastmsg + 1;
10080 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10081
10082
10083 if (play_auto) {
10084 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10085 if (vms.urgentmessages) {
10086 in_urgent = 1;
10087 res = open_mailbox(&vms, vmu, 11);
10088 } else {
10089 in_urgent = 0;
10090 res = open_mailbox(&vms, vmu, play_folder);
10091 }
10092 if (res < 0)
10093 goto out;
10094
10095
10096 if (vms.lastmsg == -1) {
10097 in_urgent = 0;
10098 cmd = vm_browse_messages(chan, &vms, vmu);
10099 res = 0;
10100 goto out;
10101 }
10102 } else {
10103 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10104
10105 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10106 in_urgent = 0;
10107 play_folder = 1;
10108 if (res < 0)
10109 goto out;
10110 } else if (!vms.urgentmessages && vms.newmessages) {
10111
10112 in_urgent = 0;
10113 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10114 if (res < 0)
10115 goto out;
10116 }
10117 }
10118
10119 if (useadsi)
10120 adsi_status(chan, &vms);
10121 res = 0;
10122
10123
10124 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10125 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10126 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10127 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10128 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10129 if ((cmd == 't') || (cmd == '#')) {
10130
10131 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10132 res = 0;
10133 goto out;
10134 } else if (cmd < 0) {
10135
10136 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10137 res = -1;
10138 goto out;
10139 }
10140 }
10141 #ifdef IMAP_STORAGE
10142 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10143 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10144 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10145 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10146 }
10147 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10148 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10149 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10150 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10151 }
10152 #endif
10153
10154 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10155 if (play_auto) {
10156 cmd = '1';
10157 } else {
10158 cmd = vm_intro(chan, vmu, &vms);
10159 }
10160 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10161
10162 vms.repeats = 0;
10163 vms.starting = 1;
10164 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10165
10166 switch (cmd) {
10167 case '1':
10168 vms.curmsg = 0;
10169
10170 case '5':
10171 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10172 cmd = vm_browse_messages(chan, &vms, vmu);
10173 break;
10174 case '2':
10175 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10176 if (useadsi)
10177 adsi_folders(chan, 0, "Change to folder...");
10178
10179 cmd = get_folder2(chan, "vm-changeto", 0);
10180 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10181 if (cmd == '#') {
10182 cmd = 0;
10183 } else if (cmd > 0) {
10184 cmd = cmd - '0';
10185 res = close_mailbox(&vms, vmu);
10186 if (res == ERROR_LOCK_PATH)
10187 goto out;
10188
10189 if (cmd != 11) in_urgent = 0;
10190 res = open_mailbox(&vms, vmu, cmd);
10191 if (res < 0)
10192 goto out;
10193 play_folder = cmd;
10194 cmd = 0;
10195 }
10196 if (useadsi)
10197 adsi_status2(chan, &vms);
10198
10199 if (!cmd) {
10200 cmd = vm_play_folder_name(chan, vms.vmbox);
10201 }
10202
10203 vms.starting = 1;
10204 vms.curmsg = 0;
10205 break;
10206 case '3':
10207 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10208 cmd = 0;
10209 vms.repeats = 0;
10210 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10211 switch (cmd) {
10212 case '1':
10213 if (vms.lastmsg > -1 && !vms.starting) {
10214 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10215 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10216 res = cmd;
10217 goto out;
10218 }
10219 } else {
10220 cmd = ast_play_and_wait(chan, "vm-sorry");
10221 }
10222 cmd = 't';
10223 break;
10224 case '2':
10225 if (!vms.starting)
10226 ast_verb(3, "Callback Requested\n");
10227 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10228 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10229 if (cmd == 9) {
10230 silentexit = 1;
10231 goto out;
10232 } else if (cmd == ERROR_LOCK_PATH) {
10233 res = cmd;
10234 goto out;
10235 }
10236 } else {
10237 cmd = ast_play_and_wait(chan, "vm-sorry");
10238 }
10239 cmd = 't';
10240 break;
10241 case '3':
10242 if (vms.lastmsg > -1 && !vms.starting) {
10243 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10244 if (cmd == ERROR_LOCK_PATH) {
10245 res = cmd;
10246 goto out;
10247 }
10248 } else {
10249 cmd = ast_play_and_wait(chan, "vm-sorry");
10250 }
10251 cmd = 't';
10252 break;
10253 case '4':
10254 if (!ast_strlen_zero(vmu->dialout)) {
10255 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10256 if (cmd == 9) {
10257 silentexit = 1;
10258 goto out;
10259 }
10260 } else {
10261 cmd = ast_play_and_wait(chan, "vm-sorry");
10262 }
10263 cmd = 't';
10264 break;
10265
10266 case '5':
10267 if (ast_test_flag(vmu, VM_SVMAIL)) {
10268 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10269 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10270 res = cmd;
10271 goto out;
10272 }
10273 } else {
10274 cmd = ast_play_and_wait(chan, "vm-sorry");
10275 }
10276 cmd = 't';
10277 break;
10278
10279 case '*':
10280 cmd = 't';
10281 break;
10282
10283 default:
10284 cmd = 0;
10285 if (!vms.starting) {
10286 cmd = ast_play_and_wait(chan, "vm-toreply");
10287 }
10288 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10289 cmd = ast_play_and_wait(chan, "vm-tocallback");
10290 }
10291 if (!cmd && !vms.starting) {
10292 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10293 }
10294 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10295 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10296 }
10297 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10298 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10299 }
10300 if (!cmd) {
10301 cmd = ast_play_and_wait(chan, "vm-starmain");
10302 }
10303 if (!cmd) {
10304 cmd = ast_waitfordigit(chan, 6000);
10305 }
10306 if (!cmd) {
10307 vms.repeats++;
10308 }
10309 if (vms.repeats > 3) {
10310 cmd = 't';
10311 }
10312 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10313 }
10314 }
10315 if (cmd == 't') {
10316 cmd = 0;
10317 vms.repeats = 0;
10318 }
10319 break;
10320 case '4':
10321 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10322 if (vms.curmsg > 0) {
10323 vms.curmsg--;
10324 cmd = play_message(chan, vmu, &vms);
10325 } else {
10326
10327
10328
10329
10330 if (in_urgent == 0 && vms.urgentmessages > 0) {
10331
10332 in_urgent = 1;
10333 res = close_mailbox(&vms, vmu);
10334 if (res == ERROR_LOCK_PATH)
10335 goto out;
10336 res = open_mailbox(&vms, vmu, 11);
10337 if (res < 0)
10338 goto out;
10339 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10340 vms.curmsg = vms.lastmsg;
10341 if (vms.lastmsg < 0) {
10342 cmd = ast_play_and_wait(chan, "vm-nomore");
10343 }
10344 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10345 vms.curmsg = vms.lastmsg;
10346 cmd = play_message(chan, vmu, &vms);
10347 } else {
10348 cmd = ast_play_and_wait(chan, "vm-nomore");
10349 }
10350 }
10351 break;
10352 case '6':
10353 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10354 if (vms.curmsg < vms.lastmsg) {
10355 vms.curmsg++;
10356 cmd = play_message(chan, vmu, &vms);
10357 } else {
10358 if (in_urgent && vms.newmessages > 0) {
10359
10360
10361
10362
10363 in_urgent = 0;
10364 res = close_mailbox(&vms, vmu);
10365 if (res == ERROR_LOCK_PATH)
10366 goto out;
10367 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10368 if (res < 0)
10369 goto out;
10370 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10371 vms.curmsg = -1;
10372 if (vms.lastmsg < 0) {
10373 cmd = ast_play_and_wait(chan, "vm-nomore");
10374 }
10375 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10376 vms.curmsg = 0;
10377 cmd = play_message(chan, vmu, &vms);
10378 } else {
10379 cmd = ast_play_and_wait(chan, "vm-nomore");
10380 }
10381 }
10382 break;
10383 case '7':
10384 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10385 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10386 if (useadsi)
10387 adsi_delete(chan, &vms);
10388 if (vms.deleted[vms.curmsg]) {
10389 if (play_folder == 0) {
10390 if (in_urgent) {
10391 vms.urgentmessages--;
10392 } else {
10393 vms.newmessages--;
10394 }
10395 }
10396 else if (play_folder == 1)
10397 vms.oldmessages--;
10398 cmd = ast_play_and_wait(chan, "vm-deleted");
10399 } else {
10400 if (play_folder == 0) {
10401 if (in_urgent) {
10402 vms.urgentmessages++;
10403 } else {
10404 vms.newmessages++;
10405 }
10406 }
10407 else if (play_folder == 1)
10408 vms.oldmessages++;
10409 cmd = ast_play_and_wait(chan, "vm-undeleted");
10410 }
10411 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10412 if (vms.curmsg < vms.lastmsg) {
10413 vms.curmsg++;
10414 cmd = play_message(chan, vmu, &vms);
10415 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10416 vms.curmsg = 0;
10417 cmd = play_message(chan, vmu, &vms);
10418 } else {
10419
10420
10421
10422
10423 if (in_urgent == 1) {
10424
10425 in_urgent = 0;
10426 res = close_mailbox(&vms, vmu);
10427 if (res == ERROR_LOCK_PATH)
10428 goto out;
10429 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10430 if (res < 0)
10431 goto out;
10432 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10433 vms.curmsg = -1;
10434 if (vms.lastmsg < 0) {
10435 cmd = ast_play_and_wait(chan, "vm-nomore");
10436 }
10437 } else {
10438 cmd = ast_play_and_wait(chan, "vm-nomore");
10439 }
10440 }
10441 }
10442 } else
10443 cmd = 0;
10444 #ifdef IMAP_STORAGE
10445 deleted = 1;
10446 #endif
10447 break;
10448
10449 case '8':
10450 if (vms.lastmsg > -1) {
10451 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10452 if (cmd == ERROR_LOCK_PATH) {
10453 res = cmd;
10454 goto out;
10455 }
10456 } else {
10457
10458
10459
10460
10461 if (in_urgent == 1 && vms.newmessages > 0) {
10462
10463 in_urgent = 0;
10464 res = close_mailbox(&vms, vmu);
10465 if (res == ERROR_LOCK_PATH)
10466 goto out;
10467 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10468 if (res < 0)
10469 goto out;
10470 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10471 vms.curmsg = -1;
10472 if (vms.lastmsg < 0) {
10473 cmd = ast_play_and_wait(chan, "vm-nomore");
10474 }
10475 } else {
10476 cmd = ast_play_and_wait(chan, "vm-nomore");
10477 }
10478 }
10479 break;
10480 case '9':
10481 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10482 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10483
10484 cmd = 0;
10485 break;
10486 }
10487 if (useadsi)
10488 adsi_folders(chan, 1, "Save to folder...");
10489 cmd = get_folder2(chan, "vm-savefolder", 1);
10490 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10491 box = 0;
10492 if (cmd == '#') {
10493 cmd = 0;
10494 break;
10495 } else if (cmd > 0) {
10496 box = cmd = cmd - '0';
10497 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10498 if (cmd == ERROR_LOCK_PATH) {
10499 res = cmd;
10500 goto out;
10501 #ifndef IMAP_STORAGE
10502 } else if (!cmd) {
10503 vms.deleted[vms.curmsg] = 1;
10504 #endif
10505 } else {
10506 vms.deleted[vms.curmsg] = 0;
10507 vms.heard[vms.curmsg] = 0;
10508 }
10509 }
10510 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10511 if (useadsi)
10512 adsi_message(chan, &vms);
10513 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10514 if (!cmd) {
10515 cmd = ast_play_and_wait(chan, "vm-message");
10516 if (!cmd)
10517 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10518 if (!cmd)
10519 cmd = ast_play_and_wait(chan, "vm-savedto");
10520 if (!cmd)
10521 cmd = vm_play_folder_name(chan, vms.fn);
10522 } else {
10523 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10524 }
10525 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10526 if (vms.curmsg < vms.lastmsg) {
10527 vms.curmsg++;
10528 cmd = play_message(chan, vmu, &vms);
10529 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10530 vms.curmsg = 0;
10531 cmd = play_message(chan, vmu, &vms);
10532 } else {
10533
10534
10535
10536
10537 if (in_urgent == 1 && vms.newmessages > 0) {
10538
10539 in_urgent = 0;
10540 res = close_mailbox(&vms, vmu);
10541 if (res == ERROR_LOCK_PATH)
10542 goto out;
10543 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10544 if (res < 0)
10545 goto out;
10546 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10547 vms.curmsg = -1;
10548 if (vms.lastmsg < 0) {
10549 cmd = ast_play_and_wait(chan, "vm-nomore");
10550 }
10551 } else {
10552 cmd = ast_play_and_wait(chan, "vm-nomore");
10553 }
10554 }
10555 }
10556 break;
10557 case '*':
10558 if (!vms.starting) {
10559 cmd = ast_play_and_wait(chan, "vm-onefor");
10560 if (!strncasecmp(chan->language, "he", 2)) {
10561 cmd = ast_play_and_wait(chan, "vm-for");
10562 }
10563 if (!cmd)
10564 cmd = vm_play_folder_name(chan, vms.vmbox);
10565 if (!cmd)
10566 cmd = ast_play_and_wait(chan, "vm-opts");
10567 if (!cmd)
10568 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10569 } else
10570 cmd = 0;
10571 break;
10572 case '0':
10573 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10574 if (useadsi)
10575 adsi_status(chan, &vms);
10576 break;
10577 default:
10578 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10579 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10580 break;
10581 }
10582 }
10583 if ((cmd == 't') || (cmd == '#')) {
10584
10585 res = 0;
10586 } else {
10587
10588 res = -1;
10589 }
10590
10591 out:
10592 if (res > -1) {
10593 ast_stopstream(chan);
10594 adsi_goodbye(chan);
10595 if (valid && res != OPERATOR_EXIT) {
10596 if (silentexit)
10597 res = ast_play_and_wait(chan, "vm-dialout");
10598 else
10599 res = ast_play_and_wait(chan, "vm-goodbye");
10600 }
10601 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10602 res = 0;
10603 }
10604 if (useadsi)
10605 ast_adsi_unload_session(chan);
10606 }
10607 if (vmu)
10608 close_mailbox(&vms, vmu);
10609 if (valid) {
10610 int new = 0, old = 0, urgent = 0;
10611 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10612 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10613
10614 run_externnotify(vmu->context, vmu->mailbox, NULL);
10615 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10616 queue_mwi_event(ext_context, urgent, new, old);
10617 }
10618 #ifdef IMAP_STORAGE
10619
10620 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10621 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10622 ast_mutex_lock(&vms.lock);
10623 #ifdef HAVE_IMAP_TK2006
10624 if (LEVELUIDPLUS (vms.mailstream)) {
10625 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10626 } else
10627 #endif
10628 mail_expunge(vms.mailstream);
10629 ast_mutex_unlock(&vms.lock);
10630 }
10631
10632
10633 if (vmu) {
10634 vmstate_delete(&vms);
10635 }
10636 #endif
10637 if (vmu)
10638 free_user(vmu);
10639
10640 #ifdef IMAP_STORAGE
10641 pthread_setspecific(ts_vmstate.key, NULL);
10642 #endif
10643 return res;
10644 }
10645
10646 static int vm_exec(struct ast_channel *chan, const char *data)
10647 {
10648 int res = 0;
10649 char *tmp;
10650 struct leave_vm_options leave_options;
10651 struct ast_flags flags = { 0 };
10652 char *opts[OPT_ARG_ARRAY_SIZE];
10653 AST_DECLARE_APP_ARGS(args,
10654 AST_APP_ARG(argv0);
10655 AST_APP_ARG(argv1);
10656 );
10657
10658 memset(&leave_options, 0, sizeof(leave_options));
10659
10660 if (chan->_state != AST_STATE_UP)
10661 ast_answer(chan);
10662
10663 if (!ast_strlen_zero(data)) {
10664 tmp = ast_strdupa(data);
10665 AST_STANDARD_APP_ARGS(args, tmp);
10666 if (args.argc == 2) {
10667 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10668 return -1;
10669 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10670 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10671 int gain;
10672
10673 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10674 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10675 return -1;
10676 } else {
10677 leave_options.record_gain = (signed char) gain;
10678 }
10679 }
10680 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10681 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10682 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10683 }
10684 }
10685 } else {
10686 char temp[256];
10687 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10688 if (res < 0)
10689 return res;
10690 if (ast_strlen_zero(temp))
10691 return 0;
10692 args.argv0 = ast_strdupa(temp);
10693 }
10694
10695 res = leave_voicemail(chan, args.argv0, &leave_options);
10696 if (res == 't') {
10697 ast_play_and_wait(chan, "vm-goodbye");
10698 res = 0;
10699 }
10700
10701 if (res == OPERATOR_EXIT) {
10702 res = 0;
10703 }
10704
10705 if (res == ERROR_LOCK_PATH) {
10706 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10707 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10708 res = 0;
10709 }
10710
10711 return res;
10712 }
10713
10714 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10715 {
10716 struct ast_vm_user *vmu;
10717
10718 if (!ast_strlen_zero(box) && box[0] == '*') {
10719 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10720 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10721 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10722 "\n\tand will be ignored.\n", box, context);
10723 return NULL;
10724 }
10725
10726 AST_LIST_TRAVERSE(&users, vmu, list) {
10727 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10728 if (strcasecmp(vmu->context, context)) {
10729 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10730 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10731 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10732 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10733 }
10734 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10735 return NULL;
10736 }
10737 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10738 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10739 return NULL;
10740 }
10741 }
10742
10743 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10744 return NULL;
10745
10746 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10747 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10748
10749 AST_LIST_INSERT_TAIL(&users, vmu, list);
10750
10751 return vmu;
10752 }
10753
10754 static int append_mailbox(const char *context, const char *box, const char *data)
10755 {
10756
10757 char *tmp;
10758 char *stringp;
10759 char *s;
10760 struct ast_vm_user *vmu;
10761 char *mailbox_full;
10762 int new = 0, old = 0, urgent = 0;
10763 char secretfn[PATH_MAX] = "";
10764
10765 tmp = ast_strdupa(data);
10766
10767 if (!(vmu = find_or_create(context, box)))
10768 return -1;
10769
10770 populate_defaults(vmu);
10771
10772 stringp = tmp;
10773 if ((s = strsep(&stringp, ","))) {
10774 if (!ast_strlen_zero(s) && s[0] == '*') {
10775 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10776 "\n\tmust be reset in voicemail.conf.\n", box);
10777 }
10778
10779 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10780 }
10781 if (stringp && (s = strsep(&stringp, ","))) {
10782 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10783 }
10784 if (stringp && (s = strsep(&stringp, ","))) {
10785 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10786 }
10787 if (stringp && (s = strsep(&stringp, ","))) {
10788 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10789 }
10790 if (stringp && (s = strsep(&stringp, ","))) {
10791 apply_options(vmu, s);
10792 }
10793
10794 switch (vmu->passwordlocation) {
10795 case OPT_PWLOC_SPOOLDIR:
10796 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10797 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10798 }
10799
10800 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
10801 strcpy(mailbox_full, box);
10802 strcat(mailbox_full, "@");
10803 strcat(mailbox_full, context);
10804
10805 inboxcount2(mailbox_full, &urgent, &new, &old);
10806 queue_mwi_event(mailbox_full, urgent, new, old);
10807
10808 return 0;
10809 }
10810
10811 AST_TEST_DEFINE(test_voicemail_vmuser)
10812 {
10813 int res = 0;
10814 struct ast_vm_user *vmu;
10815
10816 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10817 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10818 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10819 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10820 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10821 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10822 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10823 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10824 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10825 #ifdef IMAP_STORAGE
10826 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10827 "imapfolder=INBOX|imapvmshareid=6000";
10828 #endif
10829
10830 switch (cmd) {
10831 case TEST_INIT:
10832 info->name = "vmuser";
10833 info->category = "/apps/app_voicemail/";
10834 info->summary = "Vmuser unit test";
10835 info->description =
10836 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10837 return AST_TEST_NOT_RUN;
10838 case TEST_EXECUTE:
10839 break;
10840 }
10841
10842 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10843 return AST_TEST_NOT_RUN;
10844 }
10845 populate_defaults(vmu);
10846 ast_set_flag(vmu, VM_ALLOCED);
10847
10848 apply_options(vmu, options_string);
10849
10850 if (!ast_test_flag(vmu, VM_ATTACH)) {
10851 ast_test_status_update(test, "Parse failure for attach option\n");
10852 res = 1;
10853 }
10854 if (strcasecmp(vmu->attachfmt, "wav49")) {
10855 ast_test_status_update(test, "Parse failure for attachftm option\n");
10856 res = 1;
10857 }
10858 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10859 ast_test_status_update(test, "Parse failure for serveremail option\n");
10860 res = 1;
10861 }
10862 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10863 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10864 res = 1;
10865 }
10866 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10867 ast_test_status_update(test, "Parse failure for emailbody option\n");
10868 res = 1;
10869 }
10870 if (strcasecmp(vmu->zonetag, "central")) {
10871 ast_test_status_update(test, "Parse failure for tz option\n");
10872 res = 1;
10873 }
10874 if (!ast_test_flag(vmu, VM_DELETE)) {
10875 ast_test_status_update(test, "Parse failure for delete option\n");
10876 res = 1;
10877 }
10878 if (!ast_test_flag(vmu, VM_SAYCID)) {
10879 ast_test_status_update(test, "Parse failure for saycid option\n");
10880 res = 1;
10881 }
10882 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10883 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10884 res = 1;
10885 }
10886 if (!ast_test_flag(vmu, VM_REVIEW)) {
10887 ast_test_status_update(test, "Parse failure for review option\n");
10888 res = 1;
10889 }
10890 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10891 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10892 res = 1;
10893 }
10894 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10895 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10896 res = 1;
10897 }
10898 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10899 ast_test_status_update(test, "Parse failure for operator option\n");
10900 res = 1;
10901 }
10902 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10903 ast_test_status_update(test, "Parse failure for envelope option\n");
10904 res = 1;
10905 }
10906 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10907 ast_test_status_update(test, "Parse failure for moveheard option\n");
10908 res = 1;
10909 }
10910 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10911 ast_test_status_update(test, "Parse failure for sayduration option\n");
10912 res = 1;
10913 }
10914 if (vmu->saydurationm != 5) {
10915 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10916 res = 1;
10917 }
10918 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10919 ast_test_status_update(test, "Parse failure for forcename option\n");
10920 res = 1;
10921 }
10922 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10923 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10924 res = 1;
10925 }
10926 if (strcasecmp(vmu->callback, "somecontext")) {
10927 ast_test_status_update(test, "Parse failure for callbacks option\n");
10928 res = 1;
10929 }
10930 if (strcasecmp(vmu->dialout, "somecontext2")) {
10931 ast_test_status_update(test, "Parse failure for dialout option\n");
10932 res = 1;
10933 }
10934 if (strcasecmp(vmu->exit, "somecontext3")) {
10935 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10936 res = 1;
10937 }
10938 if (vmu->minsecs != 10) {
10939 ast_test_status_update(test, "Parse failure for minsecs option\n");
10940 res = 1;
10941 }
10942 if (vmu->maxsecs != 100) {
10943 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10944 res = 1;
10945 }
10946 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10947 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10948 res = 1;
10949 }
10950 if (vmu->maxdeletedmsg != 50) {
10951 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10952 res = 1;
10953 }
10954 if (vmu->volgain != 1.3) {
10955 ast_test_status_update(test, "Parse failure for volgain option\n");
10956 res = 1;
10957 }
10958 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10959 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10960 res = 1;
10961 }
10962 #ifdef IMAP_STORAGE
10963 apply_options(vmu, option_string2);
10964
10965 if (strcasecmp(vmu->imapuser, "imapuser")) {
10966 ast_test_status_update(test, "Parse failure for imapuser option\n");
10967 res = 1;
10968 }
10969 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10970 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10971 res = 1;
10972 }
10973 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10974 ast_test_status_update(test, "Parse failure for imapfolder option\n");
10975 res = 1;
10976 }
10977 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10978 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10979 res = 1;
10980 }
10981 #endif
10982
10983 free_user(vmu);
10984 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10985 }
10986
10987 static int vm_box_exists(struct ast_channel *chan, const char *data)
10988 {
10989 struct ast_vm_user svm;
10990 char *context, *box;
10991 AST_DECLARE_APP_ARGS(args,
10992 AST_APP_ARG(mbox);
10993 AST_APP_ARG(options);
10994 );
10995 static int dep_warning = 0;
10996
10997 if (ast_strlen_zero(data)) {
10998 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10999 return -1;
11000 }
11001
11002 if (!dep_warning) {
11003 dep_warning = 1;
11004 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
11005 }
11006
11007 box = ast_strdupa(data);
11008
11009 AST_STANDARD_APP_ARGS(args, box);
11010
11011 if (args.options) {
11012 }
11013
11014 if ((context = strchr(args.mbox, '@'))) {
11015 *context = '\0';
11016 context++;
11017 }
11018
11019 if (find_user(&svm, context, args.mbox)) {
11020 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11021 } else
11022 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11023
11024 return 0;
11025 }
11026
11027 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11028 {
11029 struct ast_vm_user svm;
11030 AST_DECLARE_APP_ARGS(arg,
11031 AST_APP_ARG(mbox);
11032 AST_APP_ARG(context);
11033 );
11034
11035 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11036
11037 if (ast_strlen_zero(arg.mbox)) {
11038 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11039 return -1;
11040 }
11041
11042 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11043 return 0;
11044 }
11045
11046 static struct ast_custom_function mailbox_exists_acf = {
11047 .name = "MAILBOX_EXISTS",
11048 .read = acf_mailbox_exists,
11049 };
11050
11051 static int vmauthenticate(struct ast_channel *chan, const char *data)
11052 {
11053 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11054 struct ast_vm_user vmus;
11055 char *options = NULL;
11056 int silent = 0, skipuser = 0;
11057 int res = -1;
11058
11059 if (data) {
11060 s = ast_strdupa(data);
11061 user = strsep(&s, ",");
11062 options = strsep(&s, ",");
11063 if (user) {
11064 s = user;
11065 user = strsep(&s, "@");
11066 context = strsep(&s, "");
11067 if (!ast_strlen_zero(user))
11068 skipuser++;
11069 ast_copy_string(mailbox, user, sizeof(mailbox));
11070 }
11071 }
11072
11073 if (options) {
11074 silent = (strchr(options, 's')) != NULL;
11075 }
11076
11077 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11078 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11079 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11080 ast_play_and_wait(chan, "auth-thankyou");
11081 res = 0;
11082 } else if (mailbox[0] == '*') {
11083
11084 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11085 res = 0;
11086 }
11087 }
11088
11089 return res;
11090 }
11091
11092 static char *show_users_realtime(int fd, const char *context)
11093 {
11094 struct ast_config *cfg;
11095 const char *cat = NULL;
11096
11097 if (!(cfg = ast_load_realtime_multientry("voicemail",
11098 "context", context, SENTINEL))) {
11099 return CLI_FAILURE;
11100 }
11101
11102 ast_cli(fd,
11103 "\n"
11104 "=============================================================\n"
11105 "=== Configured Voicemail Users ==============================\n"
11106 "=============================================================\n"
11107 "===\n");
11108
11109 while ((cat = ast_category_browse(cfg, cat))) {
11110 struct ast_variable *var = NULL;
11111 ast_cli(fd,
11112 "=== Mailbox ...\n"
11113 "===\n");
11114 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11115 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11116 ast_cli(fd,
11117 "===\n"
11118 "=== ---------------------------------------------------------\n"
11119 "===\n");
11120 }
11121
11122 ast_cli(fd,
11123 "=============================================================\n"
11124 "\n");
11125
11126 ast_config_destroy(cfg);
11127
11128 return CLI_SUCCESS;
11129 }
11130
11131 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11132 {
11133 int which = 0;
11134 int wordlen;
11135 struct ast_vm_user *vmu;
11136 const char *context = "";
11137
11138
11139 if (pos > 4)
11140 return NULL;
11141 if (pos == 3)
11142 return (state == 0) ? ast_strdup("for") : NULL;
11143 wordlen = strlen(word);
11144 AST_LIST_TRAVERSE(&users, vmu, list) {
11145 if (!strncasecmp(word, vmu->context, wordlen)) {
11146 if (context && strcmp(context, vmu->context) && ++which > state)
11147 return ast_strdup(vmu->context);
11148
11149 context = vmu->context;
11150 }
11151 }
11152 return NULL;
11153 }
11154
11155
11156 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11157 {
11158 struct ast_vm_user *vmu;
11159 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11160 const char *context = NULL;
11161 int users_counter = 0;
11162
11163 switch (cmd) {
11164 case CLI_INIT:
11165 e->command = "voicemail show users";
11166 e->usage =
11167 "Usage: voicemail show users [for <context>]\n"
11168 " Lists all mailboxes currently set up\n";
11169 return NULL;
11170 case CLI_GENERATE:
11171 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11172 }
11173
11174 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11175 return CLI_SHOWUSAGE;
11176 if (a->argc == 5) {
11177 if (strcmp(a->argv[3],"for"))
11178 return CLI_SHOWUSAGE;
11179 context = a->argv[4];
11180 }
11181
11182 if (ast_check_realtime("voicemail")) {
11183 if (!context) {
11184 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11185 return CLI_SHOWUSAGE;
11186 }
11187 return show_users_realtime(a->fd, context);
11188 }
11189
11190 AST_LIST_LOCK(&users);
11191 if (AST_LIST_EMPTY(&users)) {
11192 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11193 AST_LIST_UNLOCK(&users);
11194 return CLI_FAILURE;
11195 }
11196 if (!context) {
11197 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11198 } else {
11199 int count = 0;
11200 AST_LIST_TRAVERSE(&users, vmu, list) {
11201 if (!strcmp(context, vmu->context)) {
11202 count++;
11203 break;
11204 }
11205 }
11206 if (count) {
11207 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11208 } else {
11209 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11210 AST_LIST_UNLOCK(&users);
11211 return CLI_FAILURE;
11212 }
11213 }
11214 AST_LIST_TRAVERSE(&users, vmu, list) {
11215 int newmsgs = 0, oldmsgs = 0;
11216 char count[12], tmp[256] = "";
11217
11218 if (!context || !strcmp(context, vmu->context)) {
11219 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11220 inboxcount(tmp, &newmsgs, &oldmsgs);
11221 snprintf(count, sizeof(count), "%d", newmsgs);
11222 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11223 users_counter++;
11224 }
11225 }
11226 AST_LIST_UNLOCK(&users);
11227 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11228 return CLI_SUCCESS;
11229 }
11230
11231
11232 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11233 {
11234 struct vm_zone *zone;
11235 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11236 char *res = CLI_SUCCESS;
11237
11238 switch (cmd) {
11239 case CLI_INIT:
11240 e->command = "voicemail show zones";
11241 e->usage =
11242 "Usage: voicemail show zones\n"
11243 " Lists zone message formats\n";
11244 return NULL;
11245 case CLI_GENERATE:
11246 return NULL;
11247 }
11248
11249 if (a->argc != 3)
11250 return CLI_SHOWUSAGE;
11251
11252 AST_LIST_LOCK(&zones);
11253 if (!AST_LIST_EMPTY(&zones)) {
11254 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11255 AST_LIST_TRAVERSE(&zones, zone, list) {
11256 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11257 }
11258 } else {
11259 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11260 res = CLI_FAILURE;
11261 }
11262 AST_LIST_UNLOCK(&zones);
11263
11264 return res;
11265 }
11266
11267
11268 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11269 {
11270 switch (cmd) {
11271 case CLI_INIT:
11272 e->command = "voicemail reload";
11273 e->usage =
11274 "Usage: voicemail reload\n"
11275 " Reload voicemail configuration\n";
11276 return NULL;
11277 case CLI_GENERATE:
11278 return NULL;
11279 }
11280
11281 if (a->argc != 2)
11282 return CLI_SHOWUSAGE;
11283
11284 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11285 load_config(1);
11286
11287 return CLI_SUCCESS;
11288 }
11289
11290 static struct ast_cli_entry cli_voicemail[] = {
11291 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11292 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11293 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11294 };
11295
11296 #ifdef IMAP_STORAGE
11297 #define DATA_EXPORT_VM_USERS(USER) \
11298 USER(ast_vm_user, context, AST_DATA_STRING) \
11299 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11300 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11301 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11302 USER(ast_vm_user, email, AST_DATA_STRING) \
11303 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11304 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11305 USER(ast_vm_user, pager, AST_DATA_STRING) \
11306 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11307 USER(ast_vm_user, language, AST_DATA_STRING) \
11308 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11309 USER(ast_vm_user, callback, AST_DATA_STRING) \
11310 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11311 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11312 USER(ast_vm_user, exit, AST_DATA_STRING) \
11313 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11314 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11315 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11316 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11317 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11318 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11319 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11320 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11321 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11322 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11323 #else
11324 #define DATA_EXPORT_VM_USERS(USER) \
11325 USER(ast_vm_user, context, AST_DATA_STRING) \
11326 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11327 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11328 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11329 USER(ast_vm_user, email, AST_DATA_STRING) \
11330 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11331 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11332 USER(ast_vm_user, pager, AST_DATA_STRING) \
11333 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11334 USER(ast_vm_user, language, AST_DATA_STRING) \
11335 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11336 USER(ast_vm_user, callback, AST_DATA_STRING) \
11337 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11338 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11339 USER(ast_vm_user, exit, AST_DATA_STRING) \
11340 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11341 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11342 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11343 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11344 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11345 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11346 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11347 #endif
11348
11349 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11350
11351 #define DATA_EXPORT_VM_ZONES(ZONE) \
11352 ZONE(vm_zone, name, AST_DATA_STRING) \
11353 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11354 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11355
11356 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11357
11358
11359
11360
11361
11362
11363
11364
11365 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11366 struct ast_data *data_root, struct ast_vm_user *user)
11367 {
11368 struct ast_data *data_user, *data_zone;
11369 struct ast_data *data_state;
11370 struct vm_zone *zone = NULL;
11371 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11372 char ext_context[256] = "";
11373
11374 data_user = ast_data_add_node(data_root, "user");
11375 if (!data_user) {
11376 return -1;
11377 }
11378
11379 ast_data_add_structure(ast_vm_user, data_user, user);
11380
11381 AST_LIST_LOCK(&zones);
11382 AST_LIST_TRAVERSE(&zones, zone, list) {
11383 if (!strcmp(zone->name, user->zonetag)) {
11384 break;
11385 }
11386 }
11387 AST_LIST_UNLOCK(&zones);
11388
11389
11390 data_state = ast_data_add_node(data_user, "state");
11391 if (!data_state) {
11392 return -1;
11393 }
11394 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11395 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11396 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11397 ast_data_add_int(data_state, "newmsg", newmsg);
11398 ast_data_add_int(data_state, "oldmsg", oldmsg);
11399
11400 if (zone) {
11401 data_zone = ast_data_add_node(data_user, "zone");
11402 ast_data_add_structure(vm_zone, data_zone, zone);
11403 }
11404
11405 if (!ast_data_search_match(search, data_user)) {
11406 ast_data_remove_node(data_root, data_user);
11407 }
11408
11409 return 0;
11410 }
11411
11412 static int vm_users_data_provider_get(const struct ast_data_search *search,
11413 struct ast_data *data_root)
11414 {
11415 struct ast_vm_user *user;
11416
11417 AST_LIST_LOCK(&users);
11418 AST_LIST_TRAVERSE(&users, user, list) {
11419 vm_users_data_provider_get_helper(search, data_root, user);
11420 }
11421 AST_LIST_UNLOCK(&users);
11422
11423 return 0;
11424 }
11425
11426 static const struct ast_data_handler vm_users_data_provider = {
11427 .version = AST_DATA_HANDLER_VERSION,
11428 .get = vm_users_data_provider_get
11429 };
11430
11431 static const struct ast_data_entry vm_data_providers[] = {
11432 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11433 };
11434
11435 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11436 {
11437 int new = 0, old = 0, urgent = 0;
11438
11439 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11440
11441 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11442 mwi_sub->old_urgent = urgent;
11443 mwi_sub->old_new = new;
11444 mwi_sub->old_old = old;
11445 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11446 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11447 }
11448 }
11449
11450 static void poll_subscribed_mailboxes(void)
11451 {
11452 struct mwi_sub *mwi_sub;
11453
11454 AST_RWLIST_RDLOCK(&mwi_subs);
11455 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11456 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11457 poll_subscribed_mailbox(mwi_sub);
11458 }
11459 }
11460 AST_RWLIST_UNLOCK(&mwi_subs);
11461 }
11462
11463 static void *mb_poll_thread(void *data)
11464 {
11465 while (poll_thread_run) {
11466 struct timespec ts = { 0, };
11467 struct timeval wait;
11468
11469 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11470 ts.tv_sec = wait.tv_sec;
11471 ts.tv_nsec = wait.tv_usec * 1000;
11472
11473 ast_mutex_lock(&poll_lock);
11474 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11475 ast_mutex_unlock(&poll_lock);
11476
11477 if (!poll_thread_run)
11478 break;
11479
11480 poll_subscribed_mailboxes();
11481 }
11482
11483 return NULL;
11484 }
11485
11486 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11487 {
11488 ast_free(mwi_sub);
11489 }
11490
11491 static int handle_unsubscribe(void *datap)
11492 {
11493 struct mwi_sub *mwi_sub;
11494 uint32_t *uniqueid = datap;
11495
11496 AST_RWLIST_WRLOCK(&mwi_subs);
11497 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11498 if (mwi_sub->uniqueid == *uniqueid) {
11499 AST_LIST_REMOVE_CURRENT(entry);
11500 break;
11501 }
11502 }
11503 AST_RWLIST_TRAVERSE_SAFE_END
11504 AST_RWLIST_UNLOCK(&mwi_subs);
11505
11506 if (mwi_sub)
11507 mwi_sub_destroy(mwi_sub);
11508
11509 ast_free(uniqueid);
11510 return 0;
11511 }
11512
11513 static int handle_subscribe(void *datap)
11514 {
11515 unsigned int len;
11516 struct mwi_sub *mwi_sub;
11517 struct mwi_sub_task *p = datap;
11518
11519 len = sizeof(*mwi_sub);
11520 if (!ast_strlen_zero(p->mailbox))
11521 len += strlen(p->mailbox);
11522
11523 if (!ast_strlen_zero(p->context))
11524 len += strlen(p->context) + 1;
11525
11526 if (!(mwi_sub = ast_calloc(1, len)))
11527 return -1;
11528
11529 mwi_sub->uniqueid = p->uniqueid;
11530 if (!ast_strlen_zero(p->mailbox))
11531 strcpy(mwi_sub->mailbox, p->mailbox);
11532
11533 if (!ast_strlen_zero(p->context)) {
11534 strcat(mwi_sub->mailbox, "@");
11535 strcat(mwi_sub->mailbox, p->context);
11536 }
11537
11538 AST_RWLIST_WRLOCK(&mwi_subs);
11539 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11540 AST_RWLIST_UNLOCK(&mwi_subs);
11541 ast_free((void *) p->mailbox);
11542 ast_free((void *) p->context);
11543 ast_free(p);
11544 poll_subscribed_mailbox(mwi_sub);
11545 return 0;
11546 }
11547
11548 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11549 {
11550 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11551
11552 if (!uniqueid) {
11553 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11554 return;
11555 }
11556
11557 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11558 ast_free(uniqueid);
11559 return;
11560 }
11561
11562 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11563 ast_free(uniqueid);
11564 return;
11565 }
11566
11567 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11568 *uniqueid = u;
11569 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11570 ast_free(uniqueid);
11571 }
11572 }
11573
11574 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11575 {
11576 struct mwi_sub_task *mwist;
11577
11578 if (ast_event_get_type(event) != AST_EVENT_SUB)
11579 return;
11580
11581 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11582 return;
11583
11584 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11585 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11586 return;
11587 }
11588 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11589 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11590 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11591
11592 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11593 ast_free(mwist);
11594 }
11595 }
11596
11597 static void start_poll_thread(void)
11598 {
11599 int errcode;
11600 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11601 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11602 AST_EVENT_IE_END);
11603
11604 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11605 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11606 AST_EVENT_IE_END);
11607
11608 if (mwi_sub_sub)
11609 ast_event_report_subs(mwi_sub_sub);
11610
11611 poll_thread_run = 1;
11612
11613 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11614 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11615 }
11616 }
11617
11618 static void stop_poll_thread(void)
11619 {
11620 poll_thread_run = 0;
11621
11622 if (mwi_sub_sub) {
11623 ast_event_unsubscribe(mwi_sub_sub);
11624 mwi_sub_sub = NULL;
11625 }
11626
11627 if (mwi_unsub_sub) {
11628 ast_event_unsubscribe(mwi_unsub_sub);
11629 mwi_unsub_sub = NULL;
11630 }
11631
11632 ast_mutex_lock(&poll_lock);
11633 ast_cond_signal(&poll_cond);
11634 ast_mutex_unlock(&poll_lock);
11635
11636 pthread_join(poll_thread, NULL);
11637
11638 poll_thread = AST_PTHREADT_NULL;
11639 }
11640
11641
11642 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11643 {
11644 struct ast_vm_user *vmu = NULL;
11645 const char *id = astman_get_header(m, "ActionID");
11646 char actionid[128] = "";
11647
11648 if (!ast_strlen_zero(id))
11649 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11650
11651 AST_LIST_LOCK(&users);
11652
11653 if (AST_LIST_EMPTY(&users)) {
11654 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11655 AST_LIST_UNLOCK(&users);
11656 return RESULT_SUCCESS;
11657 }
11658
11659 astman_send_ack(s, m, "Voicemail user list will follow");
11660
11661 AST_LIST_TRAVERSE(&users, vmu, list) {
11662 char dirname[256];
11663
11664 #ifdef IMAP_STORAGE
11665 int new, old;
11666 inboxcount(vmu->mailbox, &new, &old);
11667 #endif
11668
11669 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11670 astman_append(s,
11671 "%s"
11672 "Event: VoicemailUserEntry\r\n"
11673 "VMContext: %s\r\n"
11674 "VoiceMailbox: %s\r\n"
11675 "Fullname: %s\r\n"
11676 "Email: %s\r\n"
11677 "Pager: %s\r\n"
11678 "ServerEmail: %s\r\n"
11679 "MailCommand: %s\r\n"
11680 "Language: %s\r\n"
11681 "TimeZone: %s\r\n"
11682 "Callback: %s\r\n"
11683 "Dialout: %s\r\n"
11684 "UniqueID: %s\r\n"
11685 "ExitContext: %s\r\n"
11686 "SayDurationMinimum: %d\r\n"
11687 "SayEnvelope: %s\r\n"
11688 "SayCID: %s\r\n"
11689 "AttachMessage: %s\r\n"
11690 "AttachmentFormat: %s\r\n"
11691 "DeleteMessage: %s\r\n"
11692 "VolumeGain: %.2f\r\n"
11693 "CanReview: %s\r\n"
11694 "CallOperator: %s\r\n"
11695 "MaxMessageCount: %d\r\n"
11696 "MaxMessageLength: %d\r\n"
11697 "NewMessageCount: %d\r\n"
11698 #ifdef IMAP_STORAGE
11699 "OldMessageCount: %d\r\n"
11700 "IMAPUser: %s\r\n"
11701 #endif
11702 "\r\n",
11703 actionid,
11704 vmu->context,
11705 vmu->mailbox,
11706 vmu->fullname,
11707 vmu->email,
11708 vmu->pager,
11709 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
11710 mailcmd,
11711 vmu->language,
11712 vmu->zonetag,
11713 vmu->callback,
11714 vmu->dialout,
11715 vmu->uniqueid,
11716 vmu->exit,
11717 vmu->saydurationm,
11718 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11719 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11720 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11721 vmu->attachfmt,
11722 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11723 vmu->volgain,
11724 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11725 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11726 vmu->maxmsg,
11727 vmu->maxsecs,
11728 #ifdef IMAP_STORAGE
11729 new, old, vmu->imapuser
11730 #else
11731 count_messages(vmu, dirname)
11732 #endif
11733 );
11734 }
11735 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11736
11737 AST_LIST_UNLOCK(&users);
11738
11739 return RESULT_SUCCESS;
11740 }
11741
11742
11743 static void free_vm_users(void)
11744 {
11745 struct ast_vm_user *current;
11746 AST_LIST_LOCK(&users);
11747 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11748 ast_set_flag(current, VM_ALLOCED);
11749 free_user(current);
11750 }
11751 AST_LIST_UNLOCK(&users);
11752 }
11753
11754
11755 static void free_vm_zones(void)
11756 {
11757 struct vm_zone *zcur;
11758 AST_LIST_LOCK(&zones);
11759 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11760 free_zone(zcur);
11761 AST_LIST_UNLOCK(&zones);
11762 }
11763
11764 static const char *substitute_escapes(const char *value)
11765 {
11766 char *current;
11767
11768
11769 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11770
11771 ast_str_reset(str);
11772
11773
11774 for (current = (char *) value; *current; current++) {
11775 if (*current == '\\') {
11776 current++;
11777 if (!*current) {
11778 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11779 break;
11780 }
11781 switch (*current) {
11782 case '\\':
11783 ast_str_append(&str, 0, "\\");
11784 break;
11785 case 'r':
11786 ast_str_append(&str, 0, "\r");
11787 break;
11788 case 'n':
11789 #ifdef IMAP_STORAGE
11790 if (!str->used || str->str[str->used - 1] != '\r') {
11791 ast_str_append(&str, 0, "\r");
11792 }
11793 #endif
11794 ast_str_append(&str, 0, "\n");
11795 break;
11796 case 't':
11797 ast_str_append(&str, 0, "\t");
11798 break;
11799 default:
11800 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11801 break;
11802 }
11803 } else {
11804 ast_str_append(&str, 0, "%c", *current);
11805 }
11806 }
11807
11808 return ast_str_buffer(str);
11809 }
11810
11811 static int load_config(int reload)
11812 {
11813 struct ast_config *cfg, *ucfg;
11814 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11815 int res;
11816
11817 ast_unload_realtime("voicemail");
11818 ast_unload_realtime("voicemail_data");
11819
11820 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11821 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11822 return 0;
11823 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11824 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11825 ucfg = NULL;
11826 }
11827 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11828 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11829 ast_config_destroy(ucfg);
11830 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11831 return 0;
11832 }
11833 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11834 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11835 return 0;
11836 } else {
11837 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11838 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11839 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11840 ucfg = NULL;
11841 }
11842 }
11843
11844 res = actual_load_config(reload, cfg, ucfg);
11845
11846 ast_config_destroy(cfg);
11847 ast_config_destroy(ucfg);
11848
11849 return res;
11850 }
11851
11852 #ifdef TEST_FRAMEWORK
11853 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11854 {
11855 ast_unload_realtime("voicemail");
11856 ast_unload_realtime("voicemail_data");
11857 return actual_load_config(reload, cfg, ucfg);
11858 }
11859 #endif
11860
11861 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11862 {
11863 struct ast_vm_user *current;
11864 char *cat;
11865 struct ast_variable *var;
11866 const char *val;
11867 char *q, *stringp, *tmp;
11868 int x;
11869 int tmpadsi[4];
11870 char secretfn[PATH_MAX] = "";
11871
11872 #ifdef IMAP_STORAGE
11873 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11874 #endif
11875
11876 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11877 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11878 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11879 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11880 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11881
11882
11883 free_vm_users();
11884
11885
11886 free_vm_zones();
11887
11888 AST_LIST_LOCK(&users);
11889
11890 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11891 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11892
11893 if (cfg) {
11894
11895
11896 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11897 val = "default";
11898 ast_copy_string(userscontext, val, sizeof(userscontext));
11899
11900 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11901 val = "yes";
11902 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11903
11904 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11905 val = "no";
11906 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11907
11908 volgain = 0.0;
11909 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11910 sscanf(val, "%30lf", &volgain);
11911
11912 #ifdef ODBC_STORAGE
11913 strcpy(odbc_database, "asterisk");
11914 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11915 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11916 }
11917 strcpy(odbc_table, "voicemessages");
11918 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11919 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11920 }
11921 #endif
11922
11923 strcpy(mailcmd, SENDMAIL);
11924 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11925 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11926
11927 maxsilence = 0;
11928 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11929 maxsilence = atoi(val);
11930 if (maxsilence > 0)
11931 maxsilence *= 1000;
11932 }
11933
11934 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11935 maxmsg = MAXMSG;
11936 } else {
11937 maxmsg = atoi(val);
11938 if (maxmsg < 0) {
11939 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11940 maxmsg = MAXMSG;
11941 } else if (maxmsg > MAXMSGLIMIT) {
11942 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11943 maxmsg = MAXMSGLIMIT;
11944 }
11945 }
11946
11947 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11948 maxdeletedmsg = 0;
11949 } else {
11950 if (sscanf(val, "%30d", &x) == 1)
11951 maxdeletedmsg = x;
11952 else if (ast_true(val))
11953 maxdeletedmsg = MAXMSG;
11954 else
11955 maxdeletedmsg = 0;
11956
11957 if (maxdeletedmsg < 0) {
11958 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11959 maxdeletedmsg = MAXMSG;
11960 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11961 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11962 maxdeletedmsg = MAXMSGLIMIT;
11963 }
11964 }
11965
11966
11967 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11968 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11969 }
11970
11971
11972 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11973 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11974 }
11975
11976
11977 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11978 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11979 pwdchange = PWDCHANGE_EXTERNAL;
11980 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11981 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11982 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11983 }
11984
11985
11986 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11987 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11988 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11989 }
11990
11991 #ifdef IMAP_STORAGE
11992
11993 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11994 ast_copy_string(imapserver, val, sizeof(imapserver));
11995 } else {
11996 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11997 }
11998
11999 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
12000 ast_copy_string(imapport, val, sizeof(imapport));
12001 } else {
12002 ast_copy_string(imapport, "143", sizeof(imapport));
12003 }
12004
12005 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
12006 ast_copy_string(imapflags, val, sizeof(imapflags));
12007 }
12008
12009 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12010 ast_copy_string(authuser, val, sizeof(authuser));
12011 }
12012
12013 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12014 ast_copy_string(authpassword, val, sizeof(authpassword));
12015 }
12016
12017 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12018 if (ast_false(val))
12019 expungeonhangup = 0;
12020 else
12021 expungeonhangup = 1;
12022 } else {
12023 expungeonhangup = 1;
12024 }
12025
12026 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12027 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12028 } else {
12029 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12030 }
12031 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12032 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12033 }
12034 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12035 imapgreetings = ast_true(val);
12036 } else {
12037 imapgreetings = 0;
12038 }
12039 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12040 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12041 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12042
12043 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12044 } else {
12045 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12046 }
12047
12048
12049
12050
12051
12052 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12053 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12054 } else {
12055 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12056 }
12057
12058 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12059 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12060 } else {
12061 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12062 }
12063
12064 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12065 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12066 } else {
12067 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12068 }
12069
12070 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12071 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12072 } else {
12073 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12074 }
12075
12076
12077 imapversion++;
12078 #endif
12079
12080 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12081 ast_copy_string(externnotify, val, sizeof(externnotify));
12082 ast_debug(1, "found externnotify: %s\n", externnotify);
12083 } else {
12084 externnotify[0] = '\0';
12085 }
12086
12087
12088 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12089 ast_debug(1, "Enabled SMDI voicemail notification\n");
12090 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12091 smdi_iface = ast_smdi_interface_find(val);
12092 } else {
12093 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12094 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12095 }
12096 if (!smdi_iface) {
12097 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12098 }
12099 }
12100
12101
12102 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12103 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12104 silencethreshold = atoi(val);
12105
12106 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12107 val = ASTERISK_USERNAME;
12108 ast_copy_string(serveremail, val, sizeof(serveremail));
12109
12110 vmmaxsecs = 0;
12111 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12112 if (sscanf(val, "%30d", &x) == 1) {
12113 vmmaxsecs = x;
12114 } else {
12115 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12116 }
12117 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12118 static int maxmessage_deprecate = 0;
12119 if (maxmessage_deprecate == 0) {
12120 maxmessage_deprecate = 1;
12121 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12122 }
12123 if (sscanf(val, "%30d", &x) == 1) {
12124 vmmaxsecs = x;
12125 } else {
12126 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12127 }
12128 }
12129
12130 vmminsecs = 0;
12131 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12132 if (sscanf(val, "%30d", &x) == 1) {
12133 vmminsecs = x;
12134 if (maxsilence / 1000 >= vmminsecs) {
12135 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12136 }
12137 } else {
12138 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12139 }
12140 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12141 static int maxmessage_deprecate = 0;
12142 if (maxmessage_deprecate == 0) {
12143 maxmessage_deprecate = 1;
12144 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12145 }
12146 if (sscanf(val, "%30d", &x) == 1) {
12147 vmminsecs = x;
12148 if (maxsilence / 1000 >= vmminsecs) {
12149 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12150 }
12151 } else {
12152 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12153 }
12154 }
12155
12156 val = ast_variable_retrieve(cfg, "general", "format");
12157 if (!val) {
12158 val = "wav";
12159 } else {
12160 tmp = ast_strdupa(val);
12161 val = ast_format_str_reduce(tmp);
12162 if (!val) {
12163 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12164 val = "wav";
12165 }
12166 }
12167 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12168
12169 skipms = 3000;
12170 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12171 if (sscanf(val, "%30d", &x) == 1) {
12172 maxgreet = x;
12173 } else {
12174 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12175 }
12176 }
12177
12178 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12179 if (sscanf(val, "%30d", &x) == 1) {
12180 skipms = x;
12181 } else {
12182 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12183 }
12184 }
12185
12186 maxlogins = 3;
12187 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12188 if (sscanf(val, "%30d", &x) == 1) {
12189 maxlogins = x;
12190 } else {
12191 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12192 }
12193 }
12194
12195 minpassword = MINPASSWORD;
12196 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12197 if (sscanf(val, "%30d", &x) == 1) {
12198 minpassword = x;
12199 } else {
12200 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12201 }
12202 }
12203
12204
12205 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12206 val = "no";
12207 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12208
12209
12210 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12211 val = "no";
12212 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12213
12214 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12215 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12216 stringp = ast_strdupa(val);
12217 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12218 if (!ast_strlen_zero(stringp)) {
12219 q = strsep(&stringp, ",");
12220 while ((*q == ' ')||(*q == '\t'))
12221 q++;
12222 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12223 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12224 } else {
12225 cidinternalcontexts[x][0] = '\0';
12226 }
12227 }
12228 }
12229 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12230 ast_debug(1, "VM Review Option disabled globally\n");
12231 val = "no";
12232 }
12233 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12234
12235
12236 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12237 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12238 val = "no";
12239 } else {
12240 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12241 }
12242 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12243 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12244 ast_debug(1, "VM next message wrap disabled globally\n");
12245 val = "no";
12246 }
12247 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12248
12249 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12250 ast_debug(1, "VM Operator break disabled globally\n");
12251 val = "no";
12252 }
12253 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12254
12255 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12256 ast_debug(1, "VM CID Info before msg disabled globally\n");
12257 val = "no";
12258 }
12259 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12260
12261 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12262 ast_debug(1, "Send Voicemail msg disabled globally\n");
12263 val = "no";
12264 }
12265 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12266
12267 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12268 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12269 val = "yes";
12270 }
12271 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12272
12273 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12274 ast_debug(1, "Move Heard enabled globally\n");
12275 val = "yes";
12276 }
12277 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12278
12279 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12280 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12281 val = "no";
12282 }
12283 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12284
12285 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12286 ast_debug(1, "Duration info before msg enabled globally\n");
12287 val = "yes";
12288 }
12289 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12290
12291 saydurationminfo = 2;
12292 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12293 if (sscanf(val, "%30d", &x) == 1) {
12294 saydurationminfo = x;
12295 } else {
12296 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12297 }
12298 }
12299
12300 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12301 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12302 val = "no";
12303 }
12304 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12305
12306 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12307 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12308 ast_debug(1, "found dialout context: %s\n", dialcontext);
12309 } else {
12310 dialcontext[0] = '\0';
12311 }
12312
12313 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12314 ast_copy_string(callcontext, val, sizeof(callcontext));
12315 ast_debug(1, "found callback context: %s\n", callcontext);
12316 } else {
12317 callcontext[0] = '\0';
12318 }
12319
12320 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12321 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12322 ast_debug(1, "found operator context: %s\n", exitcontext);
12323 } else {
12324 exitcontext[0] = '\0';
12325 }
12326
12327
12328 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12329 ast_copy_string(vm_password, val, sizeof(vm_password));
12330 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12331 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12332 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12333 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12334 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12335 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12336 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12337 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12338 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12339 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12340 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12341 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12342 }
12343 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12344 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12345 }
12346
12347 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12348 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12349 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12350 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12351 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12352 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12353 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12354 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12355 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12356 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12357
12358 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12359 val = "no";
12360 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12361
12362 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12363 val = "voicemail.conf";
12364 }
12365 if (!(strcmp(val, "spooldir"))) {
12366 passwordlocation = OPT_PWLOC_SPOOLDIR;
12367 } else {
12368 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12369 }
12370
12371 poll_freq = DEFAULT_POLL_FREQ;
12372 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12373 if (sscanf(val, "%30u", &poll_freq) != 1) {
12374 poll_freq = DEFAULT_POLL_FREQ;
12375 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12376 }
12377 }
12378
12379 poll_mailboxes = 0;
12380 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12381 poll_mailboxes = ast_true(val);
12382
12383 memset(fromstring, 0, sizeof(fromstring));
12384 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12385 strcpy(charset, "ISO-8859-1");
12386 if (emailbody) {
12387 ast_free(emailbody);
12388 emailbody = NULL;
12389 }
12390 if (emailsubject) {
12391 ast_free(emailsubject);
12392 emailsubject = NULL;
12393 }
12394 if (pagerbody) {
12395 ast_free(pagerbody);
12396 pagerbody = NULL;
12397 }
12398 if (pagersubject) {
12399 ast_free(pagersubject);
12400 pagersubject = NULL;
12401 }
12402 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12403 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12404 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12405 ast_copy_string(fromstring, val, sizeof(fromstring));
12406 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12407 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12408 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12409 ast_copy_string(charset, val, sizeof(charset));
12410 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12411 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12412 for (x = 0; x < 4; x++) {
12413 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12414 }
12415 }
12416 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12417 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12418 for (x = 0; x < 4; x++) {
12419 memcpy(&adsisec[x], &tmpadsi[x], 1);
12420 }
12421 }
12422 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12423 if (atoi(val)) {
12424 adsiver = atoi(val);
12425 }
12426 }
12427 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12428 ast_copy_string(zonetag, val, sizeof(zonetag));
12429 }
12430 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12431 ast_copy_string(locale, val, sizeof(locale));
12432 }
12433 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12434 emailsubject = ast_strdup(substitute_escapes(val));
12435 }
12436 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12437 emailbody = ast_strdup(substitute_escapes(val));
12438 }
12439 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12440 pagersubject = ast_strdup(substitute_escapes(val));
12441 }
12442 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12443 pagerbody = ast_strdup(substitute_escapes(val));
12444 }
12445
12446
12447 if (ucfg) {
12448 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12449 if (!strcasecmp(cat, "general")) {
12450 continue;
12451 }
12452 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12453 continue;
12454 if ((current = find_or_create(userscontext, cat))) {
12455 populate_defaults(current);
12456 apply_options_full(current, ast_variable_browse(ucfg, cat));
12457 ast_copy_string(current->context, userscontext, sizeof(current->context));
12458 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12459 current->passwordlocation = OPT_PWLOC_USERSCONF;
12460 }
12461
12462 switch (current->passwordlocation) {
12463 case OPT_PWLOC_SPOOLDIR:
12464 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12465 read_password_from_file(secretfn, current->password, sizeof(current->password));
12466 }
12467 }
12468 }
12469 }
12470
12471
12472 cat = ast_category_browse(cfg, NULL);
12473 while (cat) {
12474 if (strcasecmp(cat, "general")) {
12475 var = ast_variable_browse(cfg, cat);
12476 if (strcasecmp(cat, "zonemessages")) {
12477
12478 while (var) {
12479 append_mailbox(cat, var->name, var->value);
12480 var = var->next;
12481 }
12482 } else {
12483
12484 while (var) {
12485 struct vm_zone *z;
12486 if ((z = ast_malloc(sizeof(*z)))) {
12487 char *msg_format, *tzone;
12488 msg_format = ast_strdupa(var->value);
12489 tzone = strsep(&msg_format, "|,");
12490 if (msg_format) {
12491 ast_copy_string(z->name, var->name, sizeof(z->name));
12492 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12493 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12494 AST_LIST_LOCK(&zones);
12495 AST_LIST_INSERT_HEAD(&zones, z, list);
12496 AST_LIST_UNLOCK(&zones);
12497 } else {
12498 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12499 ast_free(z);
12500 }
12501 } else {
12502 AST_LIST_UNLOCK(&users);
12503 return -1;
12504 }
12505 var = var->next;
12506 }
12507 }
12508 }
12509 cat = ast_category_browse(cfg, cat);
12510 }
12511
12512 AST_LIST_UNLOCK(&users);
12513
12514 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12515 start_poll_thread();
12516 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12517 stop_poll_thread();;
12518
12519 return 0;
12520 } else {
12521 AST_LIST_UNLOCK(&users);
12522 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12523 return 0;
12524 }
12525 }
12526
12527 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12528 {
12529 int res = -1;
12530 char dir[PATH_MAX];
12531 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12532 ast_debug(2, "About to try retrieving name file %s\n", dir);
12533 RETRIEVE(dir, -1, mailbox, context);
12534 if (ast_fileexists(dir, NULL, NULL)) {
12535 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12536 }
12537 DISPOSE(dir, -1);
12538 return res;
12539 }
12540
12541 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12542 struct ast_config *pwconf;
12543 struct ast_flags config_flags = { 0 };
12544
12545 pwconf = ast_config_load(secretfn, config_flags);
12546 if (pwconf) {
12547 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12548 if (val) {
12549 ast_copy_string(password, val, passwordlen);
12550 ast_config_destroy(pwconf);
12551 return;
12552 }
12553 ast_config_destroy(pwconf);
12554 }
12555 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12556 }
12557
12558 static int write_password_to_file(const char *secretfn, const char *password) {
12559 struct ast_config *conf;
12560 struct ast_category *cat;
12561 struct ast_variable *var;
12562 int res = -1;
12563
12564 if (!(conf = ast_config_new())) {
12565 ast_log(LOG_ERROR, "Error creating new config structure\n");
12566 return res;
12567 }
12568 if (!(cat = ast_category_new("general", "", 1))) {
12569 ast_log(LOG_ERROR, "Error creating new category structure\n");
12570 ast_config_destroy(conf);
12571 return res;
12572 }
12573 if (!(var = ast_variable_new("password", password, ""))) {
12574 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12575 ast_config_destroy(conf);
12576 ast_category_destroy(cat);
12577 return res;
12578 }
12579 ast_category_append(conf, cat);
12580 ast_variable_append(cat, var);
12581 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12582 res = 0;
12583 } else {
12584 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12585 }
12586
12587 ast_config_destroy(conf);
12588 return res;
12589 }
12590
12591 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12592 {
12593 char *context;
12594 char *args_copy;
12595 int res;
12596
12597 if (ast_strlen_zero(data)) {
12598 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12599 return -1;
12600 }
12601
12602 args_copy = ast_strdupa(data);
12603 if ((context = strchr(args_copy, '@'))) {
12604 *context++ = '\0';
12605 } else {
12606 context = "default";
12607 }
12608
12609 if ((res = sayname(chan, args_copy, context) < 0)) {
12610 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12611 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12612 if (!res) {
12613 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12614 }
12615 }
12616
12617 return res;
12618 }
12619
12620 #ifdef TEST_FRAMEWORK
12621 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12622 {
12623 return 0;
12624 }
12625
12626 static struct ast_frame *fake_read(struct ast_channel *ast)
12627 {
12628 return &ast_null_frame;
12629 }
12630
12631 AST_TEST_DEFINE(test_voicemail_vmsayname)
12632 {
12633 char dir[PATH_MAX];
12634 char dir2[PATH_MAX];
12635 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12636 static const char TEST_EXTENSION[] = "1234";
12637
12638 struct ast_channel *test_channel1 = NULL;
12639 int res = -1;
12640
12641 static const struct ast_channel_tech fake_tech = {
12642 .write = fake_write,
12643 .read = fake_read,
12644 };
12645
12646 switch (cmd) {
12647 case TEST_INIT:
12648 info->name = "vmsayname_exec";
12649 info->category = "/apps/app_voicemail/";
12650 info->summary = "Vmsayname unit test";
12651 info->description =
12652 "This tests passing various parameters to vmsayname";
12653 return AST_TEST_NOT_RUN;
12654 case TEST_EXECUTE:
12655 break;
12656 }
12657
12658 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12659 NULL, NULL, 0, 0, "TestChannel1"))) {
12660 goto exit_vmsayname_test;
12661 }
12662
12663
12664 test_channel1->nativeformats = AST_FORMAT_GSM;
12665 test_channel1->writeformat = AST_FORMAT_GSM;
12666 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12667 test_channel1->readformat = AST_FORMAT_GSM;
12668 test_channel1->rawreadformat = AST_FORMAT_GSM;
12669 test_channel1->tech = &fake_tech;
12670
12671 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12672 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12673 if (!(res = vmsayname_exec(test_channel1, dir))) {
12674 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12675 if (ast_fileexists(dir, NULL, NULL)) {
12676 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12677 res = -1;
12678 goto exit_vmsayname_test;
12679 } else {
12680
12681 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12682 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12683 goto exit_vmsayname_test;
12684 }
12685 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12686 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12687
12688 if ((res = symlink(dir, dir2))) {
12689 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12690 goto exit_vmsayname_test;
12691 }
12692 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12693 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12694 res = vmsayname_exec(test_channel1, dir);
12695
12696
12697 unlink(dir2);
12698 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12699 rmdir(dir2);
12700 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12701 rmdir(dir2);
12702 }
12703 }
12704
12705 exit_vmsayname_test:
12706
12707 if (test_channel1) {
12708 ast_hangup(test_channel1);
12709 }
12710
12711 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12712 }
12713
12714 AST_TEST_DEFINE(test_voicemail_msgcount)
12715 {
12716 int i, j, res = AST_TEST_PASS, syserr;
12717 struct ast_vm_user *vmu;
12718 struct vm_state vms;
12719 #ifdef IMAP_STORAGE
12720 struct ast_channel *chan = NULL;
12721 #endif
12722 struct {
12723 char dir[256];
12724 char file[256];
12725 char txtfile[256];
12726 } tmp[3];
12727 char syscmd[256];
12728 const char origweasels[] = "tt-weasels";
12729 const char testcontext[] = "test";
12730 const char testmailbox[] = "00000000";
12731 const char testspec[] = "00000000@test";
12732 FILE *txt;
12733 int new, old, urgent;
12734 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12735 const int folder2mbox[3] = { 1, 11, 0 };
12736 const int expected_results[3][12] = {
12737
12738 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12739 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12740 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12741 };
12742
12743 switch (cmd) {
12744 case TEST_INIT:
12745 info->name = "test_voicemail_msgcount";
12746 info->category = "/apps/app_voicemail/";
12747 info->summary = "Test Voicemail status checks";
12748 info->description =
12749 "Verify that message counts are correct when retrieved through the public API";
12750 return AST_TEST_NOT_RUN;
12751 case TEST_EXECUTE:
12752 break;
12753 }
12754
12755
12756 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12757 if ((syserr = ast_safe_system(syscmd))) {
12758 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12759 syserr > 0 ? strerror(syserr) : "unable to fork()");
12760 return AST_TEST_FAIL;
12761 }
12762
12763 #ifdef IMAP_STORAGE
12764 if (!(chan = ast_dummy_channel_alloc())) {
12765 ast_test_status_update(test, "Unable to create dummy channel\n");
12766 return AST_TEST_FAIL;
12767 }
12768 #endif
12769
12770 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12771 !(vmu = find_or_create(testcontext, testmailbox))) {
12772 ast_test_status_update(test, "Cannot create vmu structure\n");
12773 ast_unreplace_sigchld();
12774 #ifdef IMAP_STORAGE
12775 chan = ast_channel_unref(chan);
12776 #endif
12777 return AST_TEST_FAIL;
12778 }
12779
12780 populate_defaults(vmu);
12781 memset(&vms, 0, sizeof(vms));
12782
12783
12784 for (i = 0; i < 3; i++) {
12785 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12786 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12787 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12788
12789 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12790 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12791 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12792 if ((syserr = ast_safe_system(syscmd))) {
12793 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12794 syserr > 0 ? strerror(syserr) : "unable to fork()");
12795 ast_unreplace_sigchld();
12796 #ifdef IMAP_STORAGE
12797 chan = ast_channel_unref(chan);
12798 #endif
12799 return AST_TEST_FAIL;
12800 }
12801 }
12802
12803 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12804 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12805 fclose(txt);
12806 } else {
12807 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12808 res = AST_TEST_FAIL;
12809 break;
12810 }
12811 open_mailbox(&vms, vmu, folder2mbox[i]);
12812 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12813
12814
12815 for (j = 0; j < 3; j++) {
12816
12817 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12818 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12819 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12820 res = AST_TEST_FAIL;
12821 }
12822 }
12823
12824 new = old = urgent = 0;
12825 if (ast_app_inboxcount(testspec, &new, &old)) {
12826 ast_test_status_update(test, "inboxcount returned failure\n");
12827 res = AST_TEST_FAIL;
12828 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12829 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12830 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12831 res = AST_TEST_FAIL;
12832 }
12833
12834 new = old = urgent = 0;
12835 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12836 ast_test_status_update(test, "inboxcount2 returned failure\n");
12837 res = AST_TEST_FAIL;
12838 } else if (old != expected_results[i][6 + 0] ||
12839 urgent != expected_results[i][6 + 1] ||
12840 new != expected_results[i][6 + 2] ) {
12841 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12842 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12843 res = AST_TEST_FAIL;
12844 }
12845
12846 new = old = urgent = 0;
12847 for (j = 0; j < 3; j++) {
12848 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12849 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12850 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12851 res = AST_TEST_FAIL;
12852 }
12853 }
12854 }
12855
12856 for (i = 0; i < 3; i++) {
12857
12858
12859
12860 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12861 DISPOSE(tmp[i].dir, 0);
12862 }
12863
12864 if (vms.deleted) {
12865 ast_free(vms.deleted);
12866 }
12867 if (vms.heard) {
12868 ast_free(vms.heard);
12869 }
12870
12871 #ifdef IMAP_STORAGE
12872 chan = ast_channel_unref(chan);
12873 #endif
12874
12875
12876 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12877 if ((syserr = ast_safe_system(syscmd))) {
12878 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12879 syserr > 0 ? strerror(syserr) : "unable to fork()");
12880 }
12881
12882 return res;
12883 }
12884
12885 AST_TEST_DEFINE(test_voicemail_notify_endl)
12886 {
12887 int res = AST_TEST_PASS;
12888 char testcontext[] = "test";
12889 char testmailbox[] = "00000000";
12890 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12891 char attach[256], attach2[256];
12892 char buf[256] = "";
12893 struct ast_channel *chan = NULL;
12894 struct ast_vm_user *vmu, vmus = {
12895 .flags = 0,
12896 };
12897 FILE *file;
12898 struct {
12899 char *name;
12900 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12901 void *location;
12902 union {
12903 int intval;
12904 char *strval;
12905 } u;
12906 } test_items[] = {
12907 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12908 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12909 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12910 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12911 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12912 { "attach2", STRPTR, attach2, .u.strval = "" },
12913 { "attach", STRPTR, attach, .u.strval = "" },
12914 };
12915 int which;
12916
12917 switch (cmd) {
12918 case TEST_INIT:
12919 info->name = "test_voicemail_notify_endl";
12920 info->category = "/apps/app_voicemail/";
12921 info->summary = "Test Voicemail notification end-of-line";
12922 info->description =
12923 "Verify that notification emails use a consistent end-of-line character";
12924 return AST_TEST_NOT_RUN;
12925 case TEST_EXECUTE:
12926 break;
12927 }
12928
12929 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12930 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12931
12932 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12933 !(vmu = find_or_create(testcontext, testmailbox))) {
12934 ast_test_status_update(test, "Cannot create vmu structure\n");
12935 return AST_TEST_NOT_RUN;
12936 }
12937
12938 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12939 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12940 return AST_TEST_NOT_RUN;
12941 }
12942
12943 populate_defaults(vmu);
12944 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12945 #ifdef IMAP_STORAGE
12946
12947 #endif
12948
12949 file = tmpfile();
12950 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12951
12952 rewind(file);
12953 if (ftruncate(fileno(file), 0)) {
12954 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12955 res = AST_TEST_FAIL;
12956 break;
12957 }
12958
12959
12960 if (test_items[which].type == INT) {
12961 *((int *) test_items[which].location) = test_items[which].u.intval;
12962 } else if (test_items[which].type == FLAGVAL) {
12963 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12964 ast_clear_flag(vmu, test_items[which].u.intval);
12965 } else {
12966 ast_set_flag(vmu, test_items[which].u.intval);
12967 }
12968 } else if (test_items[which].type == STATIC) {
12969 strcpy(test_items[which].location, test_items[which].u.strval);
12970 } else if (test_items[which].type == STRPTR) {
12971 test_items[which].location = test_items[which].u.strval;
12972 }
12973
12974 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12975 rewind(file);
12976 while (fgets(buf, sizeof(buf), file)) {
12977 if (
12978 #ifdef IMAP_STORAGE
12979 buf[strlen(buf) - 2] != '\r'
12980 #else
12981 buf[strlen(buf) - 2] == '\r'
12982 #endif
12983 || buf[strlen(buf) - 1] != '\n') {
12984 res = AST_TEST_FAIL;
12985 }
12986 }
12987 }
12988 fclose(file);
12989 return res;
12990 }
12991
12992 AST_TEST_DEFINE(test_voicemail_load_config)
12993 {
12994 int res = AST_TEST_PASS;
12995 struct ast_vm_user *vmu;
12996 struct ast_config *cfg;
12997 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
12998 int fd;
12999 FILE *file;
13000 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
13001
13002 switch (cmd) {
13003 case TEST_INIT:
13004 info->name = "test_voicemail_load_config";
13005 info->category = "/apps/app_voicemail/";
13006 info->summary = "Test loading Voicemail config";
13007 info->description =
13008 "Verify that configuration is loaded consistently. "
13009 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13010 "some options were loaded after the mailboxes were instantiated, causing "
13011 "those options not to be set correctly.";
13012 return AST_TEST_NOT_RUN;
13013 case TEST_EXECUTE:
13014 break;
13015 }
13016
13017
13018 if ((fd = mkstemp(config_filename)) < 0) {
13019 return AST_TEST_FAIL;
13020 }
13021 if (!(file = fdopen(fd, "w"))) {
13022 close(fd);
13023 unlink(config_filename);
13024 return AST_TEST_FAIL;
13025 }
13026 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13027 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13028 fputs("00000002 => 9999,Mrs. Test\n", file);
13029 fclose(file);
13030
13031 if (!(cfg = ast_config_load(config_filename, config_flags))) {
13032 res = AST_TEST_FAIL;
13033 goto cleanup;
13034 }
13035
13036 load_config_from_memory(1, cfg, NULL);
13037 ast_config_destroy(cfg);
13038
13039 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13040 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13041 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13042
13043 AST_LIST_LOCK(&users);
13044 AST_LIST_TRAVERSE(&users, vmu, list) {
13045 if (!strcmp(vmu->mailbox, "00000001")) {
13046 if (0);
13047 CHECK(vmu, callback, "othercontext")
13048 CHECK(vmu, locale, "nl_NL.UTF-8")
13049 CHECK(vmu, zonetag, "central")
13050 } else if (!strcmp(vmu->mailbox, "00000002")) {
13051 if (0);
13052 CHECK(vmu, callback, "somecontext")
13053 CHECK(vmu, locale, "de_DE.UTF-8")
13054 CHECK(vmu, zonetag, "european")
13055 }
13056 }
13057 AST_LIST_UNLOCK(&users);
13058
13059 #undef CHECK
13060
13061
13062 load_config(1);
13063
13064 cleanup:
13065 unlink(config_filename);
13066 return res;
13067 }
13068
13069 #endif
13070
13071 static int reload(void)
13072 {
13073 return load_config(1);
13074 }
13075
13076 static int unload_module(void)
13077 {
13078 int res;
13079
13080 res = ast_unregister_application(app);
13081 res |= ast_unregister_application(app2);
13082 res |= ast_unregister_application(app3);
13083 res |= ast_unregister_application(app4);
13084 res |= ast_unregister_application(sayname_app);
13085 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13086 res |= ast_manager_unregister("VoicemailUsersList");
13087 res |= ast_data_unregister(NULL);
13088 #ifdef TEST_FRAMEWORK
13089 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13090 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13091 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13092 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13093 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13094 #endif
13095 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13096 ast_uninstall_vm_functions();
13097 ao2_ref(inprocess_container, -1);
13098
13099 if (poll_thread != AST_PTHREADT_NULL)
13100 stop_poll_thread();
13101
13102 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13103 ast_unload_realtime("voicemail");
13104 ast_unload_realtime("voicemail_data");
13105
13106 free_vm_users();
13107 free_vm_zones();
13108 return res;
13109 }
13110
13111 static int load_module(void)
13112 {
13113 int res;
13114 my_umask = umask(0);
13115 umask(my_umask);
13116
13117 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13118 return AST_MODULE_LOAD_DECLINE;
13119 }
13120
13121
13122 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13123
13124 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13125 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13126 }
13127
13128 if ((res = load_config(0)))
13129 return res;
13130
13131 res = ast_register_application_xml(app, vm_exec);
13132 res |= ast_register_application_xml(app2, vm_execmain);
13133 res |= ast_register_application_xml(app3, vm_box_exists);
13134 res |= ast_register_application_xml(app4, vmauthenticate);
13135 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13136 res |= ast_custom_function_register(&mailbox_exists_acf);
13137 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13138 #ifdef TEST_FRAMEWORK
13139 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13140 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13141 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13142 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13143 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13144 #endif
13145
13146 if (res)
13147 return res;
13148
13149 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13150 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13151
13152 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13153 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13154 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13155
13156 return res;
13157 }
13158
13159 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13160 {
13161 int cmd = 0;
13162 char destination[80] = "";
13163 int retries = 0;
13164
13165 if (!num) {
13166 ast_verb(3, "Destination number will be entered manually\n");
13167 while (retries < 3 && cmd != 't') {
13168 destination[1] = '\0';
13169 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13170 if (!cmd)
13171 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13172 if (!cmd)
13173 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13174 if (!cmd) {
13175 cmd = ast_waitfordigit(chan, 6000);
13176 if (cmd)
13177 destination[0] = cmd;
13178 }
13179 if (!cmd) {
13180 retries++;
13181 } else {
13182
13183 if (cmd < 0)
13184 return 0;
13185 if (cmd == '*') {
13186 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13187 return 0;
13188 }
13189 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13190 retries++;
13191 else
13192 cmd = 't';
13193 }
13194 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13195 }
13196 if (retries >= 3) {
13197 return 0;
13198 }
13199
13200 } else {
13201 if (option_verbose > 2)
13202 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13203 ast_copy_string(destination, num, sizeof(destination));
13204 }
13205
13206 if (!ast_strlen_zero(destination)) {
13207 if (destination[strlen(destination) -1 ] == '*')
13208 return 0;
13209 if (option_verbose > 2)
13210 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13211 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13212 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13213 chan->priority = 0;
13214 return 9;
13215 }
13216 return 0;
13217 }
13218
13219
13220
13221
13222
13223
13224
13225
13226
13227
13228
13229
13230
13231
13232 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)
13233 {
13234 int res = 0;
13235 char filename[PATH_MAX];
13236 struct ast_config *msg_cfg = NULL;
13237 const char *origtime, *context;
13238 char *name, *num;
13239 int retries = 0;
13240 char *cid;
13241 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13242
13243 vms->starting = 0;
13244
13245 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13246
13247
13248 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13249 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13250 msg_cfg = ast_config_load(filename, config_flags);
13251 DISPOSE(vms->curdir, vms->curmsg);
13252 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13253 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13254 return 0;
13255 }
13256
13257 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13258 ast_config_destroy(msg_cfg);
13259 return 0;
13260 }
13261
13262 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13263
13264 context = ast_variable_retrieve(msg_cfg, "message", "context");
13265 if (!strncasecmp("macro", context, 5))
13266 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13267 switch (option) {
13268 case 3:
13269 if (!res)
13270 res = play_message_datetime(chan, vmu, origtime, filename);
13271 if (!res)
13272 res = play_message_callerid(chan, vms, cid, context, 0);
13273
13274 res = 't';
13275 break;
13276
13277 case 2:
13278
13279 if (ast_strlen_zero(cid))
13280 break;
13281
13282 ast_callerid_parse(cid, &name, &num);
13283 while ((res > -1) && (res != 't')) {
13284 switch (res) {
13285 case '1':
13286 if (num) {
13287
13288 res = dialout(chan, vmu, num, vmu->callback);
13289 if (res) {
13290 ast_config_destroy(msg_cfg);
13291 return 9;
13292 }
13293 } else {
13294 res = '2';
13295 }
13296 break;
13297
13298 case '2':
13299
13300 if (!ast_strlen_zero(vmu->dialout)) {
13301 res = dialout(chan, vmu, NULL, vmu->dialout);
13302 if (res) {
13303 ast_config_destroy(msg_cfg);
13304 return 9;
13305 }
13306 } else {
13307 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13308 res = ast_play_and_wait(chan, "vm-sorry");
13309 }
13310 ast_config_destroy(msg_cfg);
13311 return res;
13312 case '*':
13313 res = 't';
13314 break;
13315 case '3':
13316 case '4':
13317 case '5':
13318 case '6':
13319 case '7':
13320 case '8':
13321 case '9':
13322 case '0':
13323
13324 res = ast_play_and_wait(chan, "vm-sorry");
13325 retries++;
13326 break;
13327 default:
13328 if (num) {
13329 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13330 res = ast_play_and_wait(chan, "vm-num-i-have");
13331 if (!res)
13332 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13333 if (!res)
13334 res = ast_play_and_wait(chan, "vm-tocallnum");
13335
13336 if (!ast_strlen_zero(vmu->dialout)) {
13337 if (!res)
13338 res = ast_play_and_wait(chan, "vm-calldiffnum");
13339 }
13340 } else {
13341 res = ast_play_and_wait(chan, "vm-nonumber");
13342 if (!ast_strlen_zero(vmu->dialout)) {
13343 if (!res)
13344 res = ast_play_and_wait(chan, "vm-toenternumber");
13345 }
13346 }
13347 if (!res) {
13348 res = ast_play_and_wait(chan, "vm-star-cancel");
13349 }
13350 if (!res) {
13351 res = ast_waitfordigit(chan, 6000);
13352 }
13353 if (!res) {
13354 retries++;
13355 if (retries > 3) {
13356 res = 't';
13357 }
13358 }
13359 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13360 break;
13361
13362 }
13363 if (res == 't')
13364 res = 0;
13365 else if (res == '*')
13366 res = -1;
13367 }
13368 break;
13369
13370 case 1:
13371
13372 if (ast_strlen_zero(cid))
13373 break;
13374
13375 ast_callerid_parse(cid, &name, &num);
13376 if (!num) {
13377 ast_verb(3, "No CID number available, no reply sent\n");
13378 if (!res)
13379 res = ast_play_and_wait(chan, "vm-nonumber");
13380 ast_config_destroy(msg_cfg);
13381 return res;
13382 } else {
13383 struct ast_vm_user vmu2;
13384 if (find_user(&vmu2, vmu->context, num)) {
13385 struct leave_vm_options leave_options;
13386 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13387 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13388
13389 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13390
13391 memset(&leave_options, 0, sizeof(leave_options));
13392 leave_options.record_gain = record_gain;
13393 res = leave_voicemail(chan, mailbox, &leave_options);
13394 if (!res)
13395 res = 't';
13396 ast_config_destroy(msg_cfg);
13397 return res;
13398 } else {
13399
13400 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13401 ast_play_and_wait(chan, "vm-nobox");
13402 res = 't';
13403 ast_config_destroy(msg_cfg);
13404 return res;
13405 }
13406 }
13407 res = 0;
13408
13409 break;
13410 }
13411
13412 #ifndef IMAP_STORAGE
13413 ast_config_destroy(msg_cfg);
13414
13415 if (!res) {
13416 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13417 vms->heard[msg] = 1;
13418 res = wait_file(chan, vms, vms->fn);
13419 }
13420 #endif
13421 return res;
13422 }
13423
13424 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13425 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13426 signed char record_gain, struct vm_state *vms, char *flag)
13427 {
13428
13429 int res = 0;
13430 int cmd = 0;
13431 int max_attempts = 3;
13432 int attempts = 0;
13433 int recorded = 0;
13434 int msg_exists = 0;
13435 signed char zero_gain = 0;
13436 char tempfile[PATH_MAX];
13437 char *acceptdtmf = "#";
13438 char *canceldtmf = "";
13439 int canceleddtmf = 0;
13440
13441
13442
13443
13444 if (duration == NULL) {
13445 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13446 return -1;
13447 }
13448
13449 if (!outsidecaller)
13450 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13451 else
13452 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13453
13454 cmd = '3';
13455
13456 while ((cmd >= 0) && (cmd != 't')) {
13457 switch (cmd) {
13458 case '1':
13459 if (!msg_exists) {
13460
13461 cmd = '3';
13462 break;
13463 } else {
13464
13465 ast_verb(3, "Saving message as is\n");
13466 if (!outsidecaller)
13467 ast_filerename(tempfile, recordfile, NULL);
13468 ast_stream_and_wait(chan, "vm-msgsaved", "");
13469 if (!outsidecaller) {
13470
13471 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13472 DISPOSE(recordfile, -1);
13473 }
13474 cmd = 't';
13475 return res;
13476 }
13477 case '2':
13478
13479 ast_verb(3, "Reviewing the message\n");
13480 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13481 break;
13482 case '3':
13483 msg_exists = 0;
13484
13485 if (recorded == 1)
13486 ast_verb(3, "Re-recording the message\n");
13487 else
13488 ast_verb(3, "Recording the message\n");
13489
13490 if (recorded && outsidecaller) {
13491 cmd = ast_play_and_wait(chan, INTRO);
13492 cmd = ast_play_and_wait(chan, "beep");
13493 }
13494 recorded = 1;
13495
13496 if (record_gain)
13497 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13498 if (ast_test_flag(vmu, VM_OPERATOR))
13499 canceldtmf = "0";
13500 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13501 if (strchr(canceldtmf, cmd)) {
13502
13503 canceleddtmf = 1;
13504 }
13505 if (record_gain)
13506 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13507 if (cmd == -1) {
13508
13509 if (!outsidecaller) {
13510
13511 ast_filedelete(tempfile, NULL);
13512 }
13513 return cmd;
13514 }
13515 if (cmd == '0') {
13516 break;
13517 } else if (cmd == '*') {
13518 break;
13519 #if 0
13520 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13521
13522 ast_verb(3, "Message too short\n");
13523 cmd = ast_play_and_wait(chan, "vm-tooshort");
13524 cmd = ast_filedelete(tempfile, NULL);
13525 break;
13526 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13527
13528 ast_verb(3, "Nothing recorded\n");
13529 cmd = ast_filedelete(tempfile, NULL);
13530 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13531 if (!cmd)
13532 cmd = ast_play_and_wait(chan, "vm-speakup");
13533 break;
13534 #endif
13535 } else {
13536
13537 msg_exists = 1;
13538 cmd = 0;
13539 }
13540 break;
13541 case '4':
13542 if (outsidecaller) {
13543
13544 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13545 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13546 res = ast_play_and_wait(chan, "vm-marked-urgent");
13547 strcpy(flag, "Urgent");
13548 } else if (flag) {
13549 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13550 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
13551 strcpy(flag, "");
13552 } else {
13553 ast_play_and_wait(chan, "vm-sorry");
13554 }
13555 cmd = 0;
13556 } else {
13557 cmd = ast_play_and_wait(chan, "vm-sorry");
13558 }
13559 break;
13560 case '5':
13561 case '6':
13562 case '7':
13563 case '8':
13564 case '9':
13565 case '*':
13566 case '#':
13567 cmd = ast_play_and_wait(chan, "vm-sorry");
13568 break;
13569 #if 0
13570
13571
13572 case '*':
13573
13574 cmd = ast_play_and_wait(chan, "vm-deleted");
13575 cmd = ast_filedelete(tempfile, NULL);
13576 if (outsidecaller) {
13577 res = vm_exec(chan, NULL);
13578 return res;
13579 }
13580 else
13581 return 1;
13582 #endif
13583 case '0':
13584 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13585 cmd = ast_play_and_wait(chan, "vm-sorry");
13586 break;
13587 }
13588 if (msg_exists || recorded) {
13589 cmd = ast_play_and_wait(chan, "vm-saveoper");
13590 if (!cmd)
13591 cmd = ast_waitfordigit(chan, 3000);
13592 if (cmd == '1') {
13593 ast_filerename(tempfile, recordfile, NULL);
13594 ast_play_and_wait(chan, "vm-msgsaved");
13595 cmd = '0';
13596 } else if (cmd == '4') {
13597 if (flag) {
13598 ast_play_and_wait(chan, "vm-marked-urgent");
13599 strcpy(flag, "Urgent");
13600 }
13601 ast_play_and_wait(chan, "vm-msgsaved");
13602 cmd = '0';
13603 } else {
13604 ast_play_and_wait(chan, "vm-deleted");
13605 DELETE(tempfile, -1, tempfile, vmu);
13606 cmd = '0';
13607 }
13608 }
13609 return cmd;
13610 default:
13611
13612
13613
13614 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13615 return cmd;
13616 if (msg_exists) {
13617 cmd = ast_play_and_wait(chan, "vm-review");
13618 if (!cmd && outsidecaller) {
13619 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13620 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13621 } else if (flag) {
13622 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13623 }
13624 }
13625 } else {
13626 cmd = ast_play_and_wait(chan, "vm-torerecord");
13627 if (!cmd)
13628 cmd = ast_waitfordigit(chan, 600);
13629 }
13630
13631 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13632 cmd = ast_play_and_wait(chan, "vm-reachoper");
13633 if (!cmd)
13634 cmd = ast_waitfordigit(chan, 600);
13635 }
13636 #if 0
13637 if (!cmd)
13638 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13639 #endif
13640 if (!cmd)
13641 cmd = ast_waitfordigit(chan, 6000);
13642 if (!cmd) {
13643 attempts++;
13644 }
13645 if (attempts > max_attempts) {
13646 cmd = 't';
13647 }
13648 }
13649 }
13650 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13651
13652 ast_filedelete(tempfile, NULL);
13653 }
13654
13655 if (cmd != 't' && outsidecaller)
13656 ast_play_and_wait(chan, "vm-goodbye");
13657
13658 return cmd;
13659 }
13660
13661
13662
13663
13664
13665 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13666 .load = load_module,
13667 .unload = unload_module,
13668 .reload = reload,
13669 .nonoptreq = "res_adsi,res_smdi",
13670 );