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: 352643 $")
00068
00069 #include "asterisk/paths.h"
00070 #include <sys/time.h>
00071 #include <sys/stat.h>
00072 #include <sys/mman.h>
00073 #include <time.h>
00074 #include <dirent.h>
00075 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00076 #include <sys/wait.h>
00077 #endif
00078
00079 #include "asterisk/logger.h"
00080 #include "asterisk/lock.h"
00081 #include "asterisk/file.h"
00082 #include "asterisk/channel.h"
00083 #include "asterisk/pbx.h"
00084 #include "asterisk/config.h"
00085 #include "asterisk/say.h"
00086 #include "asterisk/module.h"
00087 #include "asterisk/adsi.h"
00088 #include "asterisk/app.h"
00089 #include "asterisk/manager.h"
00090 #include "asterisk/dsp.h"
00091 #include "asterisk/localtime.h"
00092 #include "asterisk/cli.h"
00093 #include "asterisk/utils.h"
00094 #include "asterisk/stringfields.h"
00095 #include "asterisk/smdi.h"
00096 #include "asterisk/astobj2.h"
00097 #include "asterisk/event.h"
00098 #include "asterisk/taskprocessor.h"
00099 #include "asterisk/test.h"
00100
00101 #ifdef ODBC_STORAGE
00102 #include "asterisk/res_odbc.h"
00103 #endif
00104
00105 #ifdef IMAP_STORAGE
00106 #include "asterisk/threadstorage.h"
00107 #endif
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 #ifdef IMAP_STORAGE
00348 static char imapserver[48];
00349 static char imapport[8];
00350 static char imapflags[128];
00351 static char imapfolder[64];
00352 static char imapparentfolder[64] = "\0";
00353 static char greetingfolder[64];
00354 static char authuser[32];
00355 static char authpassword[42];
00356 static int imapversion = 1;
00357
00358 static int expungeonhangup = 1;
00359 static int imapgreetings = 0;
00360 static char delimiter = '\0';
00361
00362 struct vm_state;
00363 struct ast_vm_user;
00364
00365 AST_THREADSTORAGE(ts_vmstate);
00366
00367
00368 static int init_mailstream(struct vm_state *vms, int box);
00369 static void write_file(char *filename, char *buffer, unsigned long len);
00370 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00371 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00372 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00373 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00374 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00375 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00376 static void vmstate_insert(struct vm_state *vms);
00377 static void vmstate_delete(struct vm_state *vms);
00378 static void set_update(MAILSTREAM * stream);
00379 static void init_vm_state(struct vm_state *vms);
00380 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00381 static void get_mailbox_delimiter(MAILSTREAM *stream);
00382 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00383 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00384 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag);
00385 static void update_messages_by_imapuser(const char *user, unsigned long number);
00386 static int vm_delete(char *file);
00387
00388 static int imap_remove_file (char *dir, int msgnum);
00389 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00390 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00391 static void check_quota(struct vm_state *vms, char *mailbox);
00392 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00393 struct vmstate {
00394 struct vm_state *vms;
00395 AST_LIST_ENTRY(vmstate) list;
00396 };
00397
00398 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00399
00400 #endif
00401
00402 #define SMDI_MWI_WAIT_TIMEOUT 1000
00403
00404 #define COMMAND_TIMEOUT 5000
00405
00406 #define VOICEMAIL_DIR_MODE 0777
00407 #define VOICEMAIL_FILE_MODE 0666
00408 #define CHUNKSIZE 65536
00409
00410 #define VOICEMAIL_CONFIG "voicemail.conf"
00411 #define ASTERISK_USERNAME "asterisk"
00412
00413
00414
00415
00416 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00417 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00418 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00419 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00420 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00421 #define VALID_DTMF "1234567890*#"
00422
00423
00424
00425 #define SENDMAIL "/usr/sbin/sendmail -t"
00426
00427 #define INTRO "vm-intro"
00428
00429 #define MAXMSG 100
00430 #define MAXMSGLIMIT 9999
00431
00432 #define MINPASSWORD 0
00433
00434 #define BASELINELEN 72
00435 #define BASEMAXINLINE 256
00436 #ifdef IMAP_STORAGE
00437 #define ENDL "\r\n"
00438 #else
00439 #define ENDL "\n"
00440 #endif
00441
00442 #define MAX_DATETIME_FORMAT 512
00443 #define MAX_NUM_CID_CONTEXTS 10
00444
00445 #define VM_REVIEW (1 << 0)
00446 #define VM_OPERATOR (1 << 1)
00447 #define VM_SAYCID (1 << 2)
00448 #define VM_SVMAIL (1 << 3)
00449 #define VM_ENVELOPE (1 << 4)
00450 #define VM_SAYDURATION (1 << 5)
00451 #define VM_SKIPAFTERCMD (1 << 6)
00452 #define VM_FORCENAME (1 << 7)
00453 #define VM_FORCEGREET (1 << 8)
00454 #define VM_PBXSKIP (1 << 9)
00455 #define VM_DIRECFORWARD (1 << 10)
00456 #define VM_ATTACH (1 << 11)
00457 #define VM_DELETE (1 << 12)
00458 #define VM_ALLOCED (1 << 13)
00459 #define VM_SEARCH (1 << 14)
00460 #define VM_TEMPGREETWARN (1 << 15)
00461 #define VM_MOVEHEARD (1 << 16)
00462 #define VM_MESSAGEWRAP (1 << 17)
00463 #define VM_FWDURGAUTO (1 << 18)
00464 #define ERROR_LOCK_PATH -100
00465 #define OPERATOR_EXIT 300
00466
00467
00468 enum vm_box {
00469 NEW_FOLDER,
00470 OLD_FOLDER,
00471 WORK_FOLDER,
00472 FAMILY_FOLDER,
00473 FRIENDS_FOLDER,
00474 GREETINGS_FOLDER
00475 };
00476
00477 enum vm_option_flags {
00478 OPT_SILENT = (1 << 0),
00479 OPT_BUSY_GREETING = (1 << 1),
00480 OPT_UNAVAIL_GREETING = (1 << 2),
00481 OPT_RECORDGAIN = (1 << 3),
00482 OPT_PREPEND_MAILBOX = (1 << 4),
00483 OPT_AUTOPLAY = (1 << 6),
00484 OPT_DTMFEXIT = (1 << 7),
00485 OPT_MESSAGE_Urgent = (1 << 8),
00486 OPT_MESSAGE_PRIORITY = (1 << 9)
00487 };
00488
00489 enum vm_option_args {
00490 OPT_ARG_RECORDGAIN = 0,
00491 OPT_ARG_PLAYFOLDER = 1,
00492 OPT_ARG_DTMFEXIT = 2,
00493
00494 OPT_ARG_ARRAY_SIZE = 3,
00495 };
00496
00497 enum vm_passwordlocation {
00498 OPT_PWLOC_VOICEMAILCONF = 0,
00499 OPT_PWLOC_SPOOLDIR = 1,
00500 OPT_PWLOC_USERSCONF = 2,
00501 };
00502
00503 AST_APP_OPTIONS(vm_app_options, {
00504 AST_APP_OPTION('s', OPT_SILENT),
00505 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00506 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00507 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00508 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00509 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00510 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00511 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00512 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00513 });
00514
00515 static int load_config(int reload);
00516 #ifdef TEST_FRAMEWORK
00517 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00518 #endif
00519 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 struct baseio {
00605 int iocp;
00606 int iolen;
00607 int linelength;
00608 int ateof;
00609 unsigned char iobuf[BASEMAXINLINE];
00610 };
00611
00612
00613
00614 struct ast_vm_user {
00615 char context[AST_MAX_CONTEXT];
00616 char mailbox[AST_MAX_EXTENSION];
00617 char password[80];
00618 char fullname[80];
00619 char email[80];
00620 char *emailsubject;
00621 char *emailbody;
00622 char pager[80];
00623 char serveremail[80];
00624 char mailcmd[160];
00625 char language[MAX_LANGUAGE];
00626 char zonetag[80];
00627 char locale[20];
00628 char callback[80];
00629 char dialout[80];
00630 char uniqueid[80];
00631 char exit[80];
00632 char attachfmt[20];
00633 unsigned int flags;
00634 int saydurationm;
00635 int minsecs;
00636 int maxmsg;
00637 int maxdeletedmsg;
00638 int maxsecs;
00639 int passwordlocation;
00640 #ifdef IMAP_STORAGE
00641 char imapuser[80];
00642 char imappassword[80];
00643 char imapfolder[64];
00644 char imapvmshareid[80];
00645 int imapversion;
00646 #endif
00647 double volgain;
00648 AST_LIST_ENTRY(ast_vm_user) list;
00649 };
00650
00651
00652 struct vm_zone {
00653 AST_LIST_ENTRY(vm_zone) list;
00654 char name[80];
00655 char timezone[80];
00656 char msg_format[512];
00657 };
00658
00659 #define VMSTATE_MAX_MSG_ARRAY 256
00660
00661
00662 struct vm_state {
00663 char curbox[80];
00664 char username[80];
00665 char context[80];
00666 char curdir[PATH_MAX];
00667 char vmbox[PATH_MAX];
00668 char fn[PATH_MAX];
00669 char intro[PATH_MAX];
00670 int *deleted;
00671 int *heard;
00672 int dh_arraysize;
00673 int curmsg;
00674 int lastmsg;
00675 int newmessages;
00676 int oldmessages;
00677 int urgentmessages;
00678 int starting;
00679 int repeats;
00680 #ifdef IMAP_STORAGE
00681 ast_mutex_t lock;
00682 int updated;
00683 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00684 MAILSTREAM *mailstream;
00685 int vmArrayIndex;
00686 char imapuser[80];
00687 char imapfolder[64];
00688 int imapversion;
00689 int interactive;
00690 char introfn[PATH_MAX];
00691 unsigned int quota_limit;
00692 unsigned int quota_usage;
00693 struct vm_state *persist_vms;
00694 #endif
00695 };
00696
00697 #ifdef ODBC_STORAGE
00698 static char odbc_database[80];
00699 static char odbc_table[80];
00700 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00701 #define DISPOSE(a,b) remove_file(a,b)
00702 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00703 #define EXISTS(a,b,c,d) (message_exists(a,b))
00704 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00705 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00706 #define DELETE(a,b,c,d) (delete_file(a,b))
00707 #else
00708 #ifdef IMAP_STORAGE
00709 #define DISPOSE(a,b) (imap_remove_file(a,b))
00710 #define STORE(a,b,c,d,e,f,g,h,i,j) (imap_store_file(a,b,c,d,e,f,g,h,i,j))
00711 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00712 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00713 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00714 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00715 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00716 #else
00717 #define RETRIEVE(a,b,c,d)
00718 #define DISPOSE(a,b)
00719 #define STORE(a,b,c,d,e,f,g,h,i,j)
00720 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00721 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00722 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00723 #define DELETE(a,b,c,d) (vm_delete(c))
00724 #endif
00725 #endif
00726
00727 static char VM_SPOOL_DIR[PATH_MAX];
00728
00729 static char ext_pass_cmd[128];
00730 static char ext_pass_check_cmd[128];
00731
00732 static int my_umask;
00733
00734 #define PWDCHANGE_INTERNAL (1 << 1)
00735 #define PWDCHANGE_EXTERNAL (1 << 2)
00736 static int pwdchange = PWDCHANGE_INTERNAL;
00737
00738 #ifdef ODBC_STORAGE
00739 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00740 #else
00741 # ifdef IMAP_STORAGE
00742 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00743 # else
00744 # define tdesc "Comedian Mail (Voicemail System)"
00745 # endif
00746 #endif
00747
00748 static char userscontext[AST_MAX_EXTENSION] = "default";
00749
00750 static char *addesc = "Comedian Mail";
00751
00752
00753 static char *app = "VoiceMail";
00754
00755
00756 static char *app2 = "VoiceMailMain";
00757
00758 static char *app3 = "MailboxExists";
00759 static char *app4 = "VMAuthenticate";
00760
00761 static char *sayname_app = "VMSayName";
00762
00763 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00764 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00765 static char zonetag[80];
00766 static char locale[20];
00767 static int maxsilence;
00768 static int maxmsg;
00769 static int maxdeletedmsg;
00770 static int silencethreshold = 128;
00771 static char serveremail[80];
00772 static char mailcmd[160];
00773 static char externnotify[160];
00774 static struct ast_smdi_interface *smdi_iface = NULL;
00775 static char vmfmts[80];
00776 static double volgain;
00777 static int vmminsecs;
00778 static int vmmaxsecs;
00779 static int maxgreet;
00780 static int skipms;
00781 static int maxlogins;
00782 static int minpassword;
00783 static int passwordlocation;
00784
00785
00786
00787 static unsigned int poll_mailboxes;
00788
00789
00790 static unsigned int poll_freq;
00791
00792 #define DEFAULT_POLL_FREQ 30
00793
00794 AST_MUTEX_DEFINE_STATIC(poll_lock);
00795 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00796 static pthread_t poll_thread = AST_PTHREADT_NULL;
00797 static unsigned char poll_thread_run;
00798
00799
00800 static struct ast_event_sub *mwi_sub_sub;
00801
00802 static struct ast_event_sub *mwi_unsub_sub;
00803
00804
00805
00806
00807
00808
00809
00810
00811 struct mwi_sub {
00812 AST_RWLIST_ENTRY(mwi_sub) entry;
00813 int old_urgent;
00814 int old_new;
00815 int old_old;
00816 uint32_t uniqueid;
00817 char mailbox[1];
00818 };
00819
00820 struct mwi_sub_task {
00821 const char *mailbox;
00822 const char *context;
00823 uint32_t uniqueid;
00824 };
00825
00826 static struct ast_taskprocessor *mwi_subscription_tps;
00827
00828 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00829
00830
00831 static char listen_control_forward_key[12];
00832 static char listen_control_reverse_key[12];
00833 static char listen_control_pause_key[12];
00834 static char listen_control_restart_key[12];
00835 static char listen_control_stop_key[12];
00836
00837
00838 static char vm_password[80] = "vm-password";
00839 static char vm_newpassword[80] = "vm-newpassword";
00840 static char vm_passchanged[80] = "vm-passchanged";
00841 static char vm_reenterpassword[80] = "vm-reenterpassword";
00842 static char vm_mismatch[80] = "vm-mismatch";
00843 static char vm_invalid_password[80] = "vm-invalid-password";
00844 static char vm_pls_try_again[80] = "vm-pls-try-again";
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856 static char vm_prepend_timeout[80] = "vm-then-pound";
00857
00858 static struct ast_flags globalflags = {0};
00859
00860 static int saydurationminfo;
00861
00862 static char dialcontext[AST_MAX_CONTEXT] = "";
00863 static char callcontext[AST_MAX_CONTEXT] = "";
00864 static char exitcontext[AST_MAX_CONTEXT] = "";
00865
00866 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00867
00868
00869 static char *emailbody = NULL;
00870 static char *emailsubject = NULL;
00871 static char *pagerbody = NULL;
00872 static char *pagersubject = NULL;
00873 static char fromstring[100];
00874 static char pagerfromstring[100];
00875 static char charset[32] = "ISO-8859-1";
00876
00877 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00878 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00879 static int adsiver = 1;
00880 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00881 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00882
00883
00884 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00885 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain);
00886 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00887 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00888 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00889 signed char record_gain, struct vm_state *vms, char *flag);
00890 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00891 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00892 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag);
00893 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag);
00894 static void apply_options(struct ast_vm_user *vmu, const char *options);
00895 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum);
00896 static int is_valid_dtmf(const char *key);
00897 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00898 static int write_password_to_file(const char *secretfn, const char *password);
00899 static const char *substitute_escapes(const char *value);
00900 static void free_user(struct ast_vm_user *vmu);
00901
00902 struct ao2_container *inprocess_container;
00903
00904 struct inprocess {
00905 int count;
00906 char *context;
00907 char mailbox[0];
00908 };
00909
00910 static int inprocess_hash_fn(const void *obj, const int flags)
00911 {
00912 const struct inprocess *i = obj;
00913 return atoi(i->mailbox);
00914 }
00915
00916 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00917 {
00918 struct inprocess *i = obj, *j = arg;
00919 if (strcmp(i->mailbox, j->mailbox)) {
00920 return 0;
00921 }
00922 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00923 }
00924
00925 static int inprocess_count(const char *context, const char *mailbox, int delta)
00926 {
00927 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00928 arg->context = arg->mailbox + strlen(mailbox) + 1;
00929 strcpy(arg->mailbox, mailbox);
00930 strcpy(arg->context, context);
00931 ao2_lock(inprocess_container);
00932 if ((i = ao2_find(inprocess_container, arg, 0))) {
00933 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00934 ao2_unlock(inprocess_container);
00935 ao2_ref(i, -1);
00936 return ret;
00937 }
00938 if (delta < 0) {
00939 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00940 }
00941 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00942 ao2_unlock(inprocess_container);
00943 return 0;
00944 }
00945 i->context = i->mailbox + strlen(mailbox) + 1;
00946 strcpy(i->mailbox, mailbox);
00947 strcpy(i->context, context);
00948 i->count = delta;
00949 ao2_link(inprocess_container, i);
00950 ao2_unlock(inprocess_container);
00951 ao2_ref(i, -1);
00952 return 0;
00953 }
00954
00955 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00956 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00957 #endif
00958
00959
00960
00961
00962
00963
00964
00965 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00966 {
00967 char *bufptr = buf;
00968 for (; *input; input++) {
00969 if (*input < 32) {
00970 continue;
00971 }
00972 *bufptr++ = *input;
00973 if (bufptr == buf + buflen - 1) {
00974 break;
00975 }
00976 }
00977 *bufptr = '\0';
00978 return buf;
00979 }
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995 static void populate_defaults(struct ast_vm_user *vmu)
00996 {
00997 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00998 vmu->passwordlocation = passwordlocation;
00999 if (saydurationminfo) {
01000 vmu->saydurationm = saydurationminfo;
01001 }
01002 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01003 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01004 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01005 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01006 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01007 if (vmminsecs) {
01008 vmu->minsecs = vmminsecs;
01009 }
01010 if (vmmaxsecs) {
01011 vmu->maxsecs = vmmaxsecs;
01012 }
01013 if (maxmsg) {
01014 vmu->maxmsg = maxmsg;
01015 }
01016 if (maxdeletedmsg) {
01017 vmu->maxdeletedmsg = maxdeletedmsg;
01018 }
01019 vmu->volgain = volgain;
01020 ast_free(vmu->emailsubject);
01021 vmu->emailsubject = NULL;
01022 ast_free(vmu->emailbody);
01023 vmu->emailbody = NULL;
01024 #ifdef IMAP_STORAGE
01025 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01026 #endif
01027 }
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01038 {
01039 int x;
01040 if (!strcasecmp(var, "attach")) {
01041 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01042 } else if (!strcasecmp(var, "attachfmt")) {
01043 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01044 } else if (!strcasecmp(var, "serveremail")) {
01045 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01046 } else if (!strcasecmp(var, "emailbody")) {
01047 vmu->emailbody = ast_strdup(substitute_escapes(value));
01048 } else if (!strcasecmp(var, "emailsubject")) {
01049 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01050 } else if (!strcasecmp(var, "language")) {
01051 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01052 } else if (!strcasecmp(var, "tz")) {
01053 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01054 } else if (!strcasecmp(var, "locale")) {
01055 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01056 #ifdef IMAP_STORAGE
01057 } else if (!strcasecmp(var, "imapuser")) {
01058 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01059 vmu->imapversion = imapversion;
01060 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01061 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01062 vmu->imapversion = imapversion;
01063 } else if (!strcasecmp(var, "imapfolder")) {
01064 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01065 } else if (!strcasecmp(var, "imapvmshareid")) {
01066 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01067 vmu->imapversion = imapversion;
01068 #endif
01069 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01070 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01071 } else if (!strcasecmp(var, "saycid")){
01072 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01073 } else if (!strcasecmp(var, "sendvoicemail")){
01074 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01075 } else if (!strcasecmp(var, "review")){
01076 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01077 } else if (!strcasecmp(var, "tempgreetwarn")){
01078 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01079 } else if (!strcasecmp(var, "messagewrap")){
01080 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01081 } else if (!strcasecmp(var, "operator")) {
01082 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01083 } else if (!strcasecmp(var, "envelope")){
01084 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01085 } else if (!strcasecmp(var, "moveheard")){
01086 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01087 } else if (!strcasecmp(var, "sayduration")){
01088 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01089 } else if (!strcasecmp(var, "saydurationm")){
01090 if (sscanf(value, "%30d", &x) == 1) {
01091 vmu->saydurationm = x;
01092 } else {
01093 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01094 }
01095 } else if (!strcasecmp(var, "forcename")){
01096 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01097 } else if (!strcasecmp(var, "forcegreetings")){
01098 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01099 } else if (!strcasecmp(var, "callback")) {
01100 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01101 } else if (!strcasecmp(var, "dialout")) {
01102 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01103 } else if (!strcasecmp(var, "exitcontext")) {
01104 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01105 } else if (!strcasecmp(var, "minsecs")) {
01106 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01107 vmu->minsecs = x;
01108 } else {
01109 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01110 vmu->minsecs = vmminsecs;
01111 }
01112 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01113 vmu->maxsecs = atoi(value);
01114 if (vmu->maxsecs <= 0) {
01115 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01116 vmu->maxsecs = vmmaxsecs;
01117 } else {
01118 vmu->maxsecs = atoi(value);
01119 }
01120 if (!strcasecmp(var, "maxmessage"))
01121 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01122 } else if (!strcasecmp(var, "maxmsg")) {
01123 vmu->maxmsg = atoi(value);
01124
01125 if (vmu->maxmsg < 0) {
01126 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01127 vmu->maxmsg = MAXMSG;
01128 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01129 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01130 vmu->maxmsg = MAXMSGLIMIT;
01131 }
01132 } else if (!strcasecmp(var, "nextaftercmd")) {
01133 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01134 } else if (!strcasecmp(var, "backupdeleted")) {
01135 if (sscanf(value, "%30d", &x) == 1)
01136 vmu->maxdeletedmsg = x;
01137 else if (ast_true(value))
01138 vmu->maxdeletedmsg = MAXMSG;
01139 else
01140 vmu->maxdeletedmsg = 0;
01141
01142 if (vmu->maxdeletedmsg < 0) {
01143 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01144 vmu->maxdeletedmsg = MAXMSG;
01145 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01146 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01147 vmu->maxdeletedmsg = MAXMSGLIMIT;
01148 }
01149 } else if (!strcasecmp(var, "volgain")) {
01150 sscanf(value, "%30lf", &vmu->volgain);
01151 } else if (!strcasecmp(var, "passwordlocation")) {
01152 if (!strcasecmp(value, "spooldir")) {
01153 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01154 } else {
01155 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01156 }
01157 } else if (!strcasecmp(var, "options")) {
01158 apply_options(vmu, value);
01159 }
01160 }
01161
01162 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01163 {
01164 int fds[2], pid = 0;
01165
01166 memset(buf, 0, len);
01167
01168 if (pipe(fds)) {
01169 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01170 } else {
01171
01172 pid = ast_safe_fork(0);
01173
01174 if (pid < 0) {
01175
01176 close(fds[0]);
01177 close(fds[1]);
01178 snprintf(buf, len, "FAILURE: Fork failed");
01179 } else if (pid) {
01180
01181 close(fds[1]);
01182 if (read(fds[0], buf, len) < 0) {
01183 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01184 }
01185 close(fds[0]);
01186 } else {
01187
01188 AST_DECLARE_APP_ARGS(arg,
01189 AST_APP_ARG(v)[20];
01190 );
01191 char *mycmd = ast_strdupa(command);
01192
01193 close(fds[0]);
01194 dup2(fds[1], STDOUT_FILENO);
01195 close(fds[1]);
01196 ast_close_fds_above_n(STDOUT_FILENO);
01197
01198 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01199
01200 execv(arg.v[0], arg.v);
01201 printf("FAILURE: %s", strerror(errno));
01202 _exit(0);
01203 }
01204 }
01205 return buf;
01206 }
01207
01208
01209
01210
01211
01212
01213
01214
01215 static int check_password(struct ast_vm_user *vmu, char *password)
01216 {
01217
01218 if (strlen(password) < minpassword)
01219 return 1;
01220
01221 if (!ast_strlen_zero(password) && password[0] == '*')
01222 return 1;
01223 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01224 char cmd[255], buf[255];
01225
01226 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01227
01228 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01229 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01230 ast_debug(5, "Result: %s\n", buf);
01231 if (!strncasecmp(buf, "VALID", 5)) {
01232 ast_debug(3, "Passed password check: '%s'\n", buf);
01233 return 0;
01234 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01235 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01236 return 0;
01237 } else {
01238 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01239 return 1;
01240 }
01241 }
01242 }
01243 return 0;
01244 }
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01257 {
01258 int res = -1;
01259 if (!strcmp(vmu->password, password)) {
01260
01261 return 0;
01262 }
01263
01264 if (strlen(password) > 10) {
01265 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01266 }
01267 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01268 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01269 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01270 res = 0;
01271 }
01272 return res;
01273 }
01274
01275
01276
01277
01278 static void apply_options(struct ast_vm_user *vmu, const char *options)
01279 {
01280 char *stringp;
01281 char *s;
01282 char *var, *value;
01283 stringp = ast_strdupa(options);
01284 while ((s = strsep(&stringp, "|"))) {
01285 value = s;
01286 if ((var = strsep(&value, "=")) && value) {
01287 apply_option(vmu, var, value);
01288 }
01289 }
01290 }
01291
01292
01293
01294
01295
01296
01297 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01298 {
01299 for (; var; var = var->next) {
01300 if (!strcasecmp(var->name, "vmsecret")) {
01301 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01302 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01303 if (ast_strlen_zero(retval->password)) {
01304 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01305 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01306 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01307 } else {
01308 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01309 }
01310 }
01311 } else if (!strcasecmp(var->name, "uniqueid")) {
01312 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01313 } else if (!strcasecmp(var->name, "pager")) {
01314 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01315 } else if (!strcasecmp(var->name, "email")) {
01316 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01317 } else if (!strcasecmp(var->name, "fullname")) {
01318 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01319 } else if (!strcasecmp(var->name, "context")) {
01320 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01321 } else if (!strcasecmp(var->name, "emailsubject")) {
01322 ast_free(retval->emailsubject);
01323 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01324 } else if (!strcasecmp(var->name, "emailbody")) {
01325 ast_free(retval->emailbody);
01326 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01327 #ifdef IMAP_STORAGE
01328 } else if (!strcasecmp(var->name, "imapuser")) {
01329 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01330 retval->imapversion = imapversion;
01331 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01332 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01333 retval->imapversion = imapversion;
01334 } else if (!strcasecmp(var->name, "imapfolder")) {
01335 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01336 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01337 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01338 retval->imapversion = imapversion;
01339 #endif
01340 } else
01341 apply_option(retval, var->name, var->value);
01342 }
01343 }
01344
01345
01346
01347
01348
01349
01350
01351
01352 static int is_valid_dtmf(const char *key)
01353 {
01354 int i;
01355 char *local_key = ast_strdupa(key);
01356
01357 for (i = 0; i < strlen(key); ++i) {
01358 if (!strchr(VALID_DTMF, *local_key)) {
01359 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01360 return 0;
01361 }
01362 local_key++;
01363 }
01364 return 1;
01365 }
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01378 {
01379 struct ast_variable *var;
01380 struct ast_vm_user *retval;
01381
01382 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01383 if (!ivm)
01384 ast_set_flag(retval, VM_ALLOCED);
01385 else
01386 memset(retval, 0, sizeof(*retval));
01387 if (mailbox)
01388 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01389 populate_defaults(retval);
01390 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01391 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01392 else
01393 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01394 if (var) {
01395 apply_options_full(retval, var);
01396 ast_variables_destroy(var);
01397 } else {
01398 if (!ivm)
01399 free_user(retval);
01400 retval = NULL;
01401 }
01402 }
01403 return retval;
01404 }
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01415 {
01416
01417 struct ast_vm_user *vmu = NULL, *cur;
01418 AST_LIST_LOCK(&users);
01419
01420 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01421 context = "default";
01422
01423 AST_LIST_TRAVERSE(&users, cur, list) {
01424 #ifdef IMAP_STORAGE
01425 if (cur->imapversion != imapversion) {
01426 continue;
01427 }
01428 #endif
01429 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01430 break;
01431 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01432 break;
01433 }
01434 if (cur) {
01435
01436 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01437 *vmu = *cur;
01438 if (!ivm) {
01439 vmu->emailbody = ast_strdup(cur->emailbody);
01440 vmu->emailsubject = ast_strdup(cur->emailsubject);
01441 }
01442 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01443 AST_LIST_NEXT(vmu, list) = NULL;
01444 }
01445 } else
01446 vmu = find_user_realtime(ivm, context, mailbox);
01447 AST_LIST_UNLOCK(&users);
01448 return vmu;
01449 }
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01462 {
01463
01464 struct ast_vm_user *cur;
01465 int res = -1;
01466 AST_LIST_LOCK(&users);
01467 AST_LIST_TRAVERSE(&users, cur, list) {
01468 if ((!context || !strcasecmp(context, cur->context)) &&
01469 (!strcasecmp(mailbox, cur->mailbox)))
01470 break;
01471 }
01472 if (cur) {
01473 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01474 res = 0;
01475 }
01476 AST_LIST_UNLOCK(&users);
01477 return res;
01478 }
01479
01480
01481
01482
01483
01484
01485
01486
01487 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01488 {
01489 struct ast_config *cfg = NULL;
01490 struct ast_variable *var = NULL;
01491 struct ast_category *cat = NULL;
01492 char *category = NULL, *value = NULL, *new = NULL;
01493 const char *tmp = NULL;
01494 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01495 char secretfn[PATH_MAX] = "";
01496 int found = 0;
01497
01498 if (!change_password_realtime(vmu, newpassword))
01499 return;
01500
01501
01502 switch (vmu->passwordlocation) {
01503 case OPT_PWLOC_SPOOLDIR:
01504 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01505 if (write_password_to_file(secretfn, newpassword) == 0) {
01506 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01507 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01508 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01509 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01510 break;
01511 } else {
01512 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01513 }
01514
01515 case OPT_PWLOC_VOICEMAILCONF:
01516 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01517 while ((category = ast_category_browse(cfg, category))) {
01518 if (!strcasecmp(category, vmu->context)) {
01519 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01520 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01521 break;
01522 }
01523 value = strstr(tmp, ",");
01524 if (!value) {
01525 new = alloca(strlen(newpassword)+1);
01526 sprintf(new, "%s", newpassword);
01527 } else {
01528 new = alloca((strlen(value) + strlen(newpassword) + 1));
01529 sprintf(new, "%s%s", newpassword, value);
01530 }
01531 if (!(cat = ast_category_get(cfg, category))) {
01532 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01533 break;
01534 }
01535 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01536 found = 1;
01537 }
01538 }
01539
01540 if (found) {
01541 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01542 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01543 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01544 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01545 break;
01546 }
01547 }
01548
01549 case OPT_PWLOC_USERSCONF:
01550
01551
01552 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01553 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01554 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01555 ast_debug(4, "users.conf: %s\n", category);
01556 if (!strcasecmp(category, vmu->mailbox)) {
01557 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01558 ast_debug(3, "looks like we need to make vmsecret!\n");
01559 var = ast_variable_new("vmsecret", newpassword, "");
01560 } else {
01561 var = NULL;
01562 }
01563 new = alloca(strlen(newpassword) + 1);
01564 sprintf(new, "%s", newpassword);
01565 if (!(cat = ast_category_get(cfg, category))) {
01566 ast_debug(4, "failed to get category!\n");
01567 ast_free(var);
01568 break;
01569 }
01570 if (!var) {
01571 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01572 } else {
01573 ast_variable_append(cat, var);
01574 }
01575 found = 1;
01576 break;
01577 }
01578 }
01579
01580 if (found) {
01581 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01582 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01583 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01584 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01585 }
01586 }
01587 }
01588 }
01589
01590 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01591 {
01592 char buf[255];
01593 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01594 ast_debug(1, "External password: %s\n",buf);
01595 if (!ast_safe_system(buf)) {
01596 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01597 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01598
01599 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01600 }
01601 }
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01617 {
01618 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01619 }
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633 static int make_file(char *dest, const int len, const char *dir, const int num)
01634 {
01635 return snprintf(dest, len, "%s/msg%04d", dir, num);
01636 }
01637
01638
01639 static FILE *vm_mkftemp(char *template)
01640 {
01641 FILE *p = NULL;
01642 int pfd = mkstemp(template);
01643 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01644 if (pfd > -1) {
01645 p = fdopen(pfd, "w+");
01646 if (!p) {
01647 close(pfd);
01648 pfd = -1;
01649 }
01650 }
01651 return p;
01652 }
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01663 {
01664 mode_t mode = VOICEMAIL_DIR_MODE;
01665 int res;
01666
01667 make_dir(dest, len, context, ext, folder);
01668 if ((res = ast_mkdir(dest, mode))) {
01669 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01670 return -1;
01671 }
01672 return 0;
01673 }
01674
01675 static const char * const mailbox_folders[] = {
01676 #ifdef IMAP_STORAGE
01677 imapfolder,
01678 #else
01679 "INBOX",
01680 #endif
01681 "Old",
01682 "Work",
01683 "Family",
01684 "Friends",
01685 "Cust1",
01686 "Cust2",
01687 "Cust3",
01688 "Cust4",
01689 "Cust5",
01690 "Deleted",
01691 "Urgent",
01692 };
01693
01694 static const char *mbox(struct ast_vm_user *vmu, int id)
01695 {
01696 #ifdef IMAP_STORAGE
01697 if (vmu && id == 0) {
01698 return vmu->imapfolder;
01699 }
01700 #endif
01701 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01702 }
01703
01704 static int get_folder_by_name(const char *name)
01705 {
01706 size_t i;
01707
01708 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01709 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01710 return i;
01711 }
01712 }
01713
01714 return -1;
01715 }
01716
01717 static void free_user(struct ast_vm_user *vmu)
01718 {
01719 if (ast_test_flag(vmu, VM_ALLOCED)) {
01720
01721 ast_free(vmu->emailbody);
01722 vmu->emailbody = NULL;
01723
01724 ast_free(vmu->emailsubject);
01725 vmu->emailsubject = NULL;
01726
01727 ast_free(vmu);
01728 }
01729 }
01730
01731 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01732
01733 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01734 if (!vms->dh_arraysize) {
01735
01736 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01737 return -1;
01738 }
01739 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01740 return -1;
01741 }
01742 vms->dh_arraysize = arraysize;
01743 } else if (vms->dh_arraysize < arraysize) {
01744 if (!(vms->deleted = ast_realloc(vms->deleted, arraysize * sizeof(int)))) {
01745 return -1;
01746 }
01747 if (!(vms->heard = ast_realloc(vms->heard, arraysize * sizeof(int)))) {
01748 return -1;
01749 }
01750 memset(vms->deleted, 0, arraysize * sizeof(int));
01751 memset(vms->heard, 0, arraysize * sizeof(int));
01752 vms->dh_arraysize = arraysize;
01753 }
01754
01755 return 0;
01756 }
01757
01758
01759
01760 #ifdef IMAP_STORAGE
01761 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01762 {
01763 char arg[10];
01764 struct vm_state *vms;
01765 unsigned long messageNum;
01766
01767
01768 if (msgnum < 0 && !imapgreetings) {
01769 ast_filedelete(file, NULL);
01770 return;
01771 }
01772
01773 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01774 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);
01775 return;
01776 }
01777
01778
01779
01780 messageNum = vms->msgArray[msgnum];
01781 if (messageNum == 0) {
01782 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01783 return;
01784 }
01785 if (option_debug > 2)
01786 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01787
01788 snprintf (arg, sizeof(arg), "%lu", messageNum);
01789 ast_mutex_lock(&vms->lock);
01790 mail_setflag (vms->mailstream, arg, "\\DELETED");
01791 mail_expunge(vms->mailstream);
01792 ast_mutex_unlock(&vms->lock);
01793 }
01794
01795 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01796 {
01797 struct vm_state *vms_p;
01798 char *file, *filename;
01799 char *attachment;
01800 int i;
01801 BODY *body;
01802
01803
01804
01805
01806 if (msgnum > -1 || !imapgreetings) {
01807 return 0;
01808 } else {
01809 file = strrchr(ast_strdupa(dir), '/');
01810 if (file)
01811 *file++ = '\0';
01812 else {
01813 ast_debug (1, "Failed to procure file name from directory passed.\n");
01814 return -1;
01815 }
01816 }
01817
01818
01819 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01820 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01821
01822
01823
01824
01825 if (!(vms_p = create_vm_state_from_user(vmu))) {
01826 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01827 return -1;
01828 }
01829 }
01830
01831
01832 *vms_p->introfn = '\0';
01833
01834 ast_mutex_lock(&vms_p->lock);
01835 init_mailstream(vms_p, GREETINGS_FOLDER);
01836 if (!vms_p->mailstream) {
01837 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01838 ast_mutex_unlock(&vms_p->lock);
01839 return -1;
01840 }
01841
01842
01843 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01844 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01845
01846 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01847 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01848 } else {
01849 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01850 ast_mutex_unlock(&vms_p->lock);
01851 return -1;
01852 }
01853 filename = strsep(&attachment, ".");
01854 if (!strcmp(filename, file)) {
01855 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01856 vms_p->msgArray[vms_p->curmsg] = i + 1;
01857 save_body(body, vms_p, "2", attachment, 0);
01858 ast_mutex_unlock(&vms_p->lock);
01859 return 0;
01860 }
01861 }
01862 ast_mutex_unlock(&vms_p->lock);
01863
01864 return -1;
01865 }
01866
01867 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01868 {
01869 BODY *body;
01870 char *header_content;
01871 char *attachedfilefmt;
01872 char buf[80];
01873 struct vm_state *vms;
01874 char text_file[PATH_MAX];
01875 FILE *text_file_ptr;
01876 int res = 0;
01877 struct ast_vm_user *vmu;
01878
01879 if (!(vmu = find_user(NULL, context, mailbox))) {
01880 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01881 return -1;
01882 }
01883
01884 if (msgnum < 0) {
01885 if (imapgreetings) {
01886 res = imap_retrieve_greeting(dir, msgnum, vmu);
01887 goto exit;
01888 } else {
01889 res = 0;
01890 goto exit;
01891 }
01892 }
01893
01894
01895
01896
01897 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01898
01899
01900
01901
01902
01903
01904
01905 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01906 res = -1;
01907 goto exit;
01908 }
01909
01910 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01911 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01912
01913
01914 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01915 res = 0;
01916 goto exit;
01917 }
01918
01919 if (option_debug > 2)
01920 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01921 if (vms->msgArray[msgnum] == 0) {
01922 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01923 res = -1;
01924 goto exit;
01925 }
01926
01927
01928 ast_mutex_lock(&vms->lock);
01929 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01930 ast_mutex_unlock(&vms->lock);
01931
01932 if (ast_strlen_zero(header_content)) {
01933 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01934 res = -1;
01935 goto exit;
01936 }
01937
01938 ast_mutex_lock(&vms->lock);
01939 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01940 ast_mutex_unlock(&vms->lock);
01941
01942
01943 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01944 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01945 } else {
01946 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01947 res = -1;
01948 goto exit;
01949 }
01950
01951
01952
01953 strsep(&attachedfilefmt, ".");
01954 if (!attachedfilefmt) {
01955 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01956 res = -1;
01957 goto exit;
01958 }
01959
01960 save_body(body, vms, "2", attachedfilefmt, 0);
01961 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01962 *vms->introfn = '\0';
01963 }
01964
01965
01966 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01967
01968 if (!(text_file_ptr = fopen(text_file, "w"))) {
01969 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01970 }
01971
01972 fprintf(text_file_ptr, "%s\n", "[message]");
01973
01974 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01975 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01976 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01977 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01978 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01979 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
01980 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
01981 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
01982 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
01983 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
01984 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
01985 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
01986 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
01987 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
01988 fclose(text_file_ptr);
01989
01990 exit:
01991 free_user(vmu);
01992 return res;
01993 }
01994
01995 static int folder_int(const char *folder)
01996 {
01997
01998 if (!folder) {
01999 return 0;
02000 }
02001 if (!strcasecmp(folder, imapfolder)) {
02002 return 0;
02003 } else if (!strcasecmp(folder, "Old")) {
02004 return 1;
02005 } else if (!strcasecmp(folder, "Work")) {
02006 return 2;
02007 } else if (!strcasecmp(folder, "Family")) {
02008 return 3;
02009 } else if (!strcasecmp(folder, "Friends")) {
02010 return 4;
02011 } else if (!strcasecmp(folder, "Cust1")) {
02012 return 5;
02013 } else if (!strcasecmp(folder, "Cust2")) {
02014 return 6;
02015 } else if (!strcasecmp(folder, "Cust3")) {
02016 return 7;
02017 } else if (!strcasecmp(folder, "Cust4")) {
02018 return 8;
02019 } else if (!strcasecmp(folder, "Cust5")) {
02020 return 9;
02021 } else if (!strcasecmp(folder, "Urgent")) {
02022 return 11;
02023 } else {
02024 return 0;
02025 }
02026 }
02027
02028 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02029 {
02030 SEARCHPGM *pgm;
02031 SEARCHHEADER *hdr;
02032
02033 struct ast_vm_user *vmu, vmus;
02034 struct vm_state *vms_p;
02035 int ret = 0;
02036 int fold = folder_int(folder);
02037 int urgent = 0;
02038
02039
02040 if (fold == 11) {
02041 fold = NEW_FOLDER;
02042 urgent = 1;
02043 }
02044
02045 if (ast_strlen_zero(mailbox))
02046 return 0;
02047
02048
02049 vmu = find_user(&vmus, context, mailbox);
02050 if (!vmu) {
02051 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02052 return -1;
02053 } else {
02054
02055 if (vmu->imapuser[0] == '\0') {
02056 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02057 return -1;
02058 }
02059 }
02060
02061
02062 if (vmu->imapuser[0] == '\0') {
02063 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02064 free_user(vmu);
02065 return -1;
02066 }
02067
02068
02069 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02070 if (!vms_p) {
02071 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02072 }
02073 if (vms_p) {
02074 ast_debug(3, "Returning before search - user is logged in\n");
02075 if (fold == 0) {
02076 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02077 }
02078 if (fold == 1) {
02079 return vms_p->oldmessages;
02080 }
02081 }
02082
02083
02084 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02085 if (!vms_p) {
02086 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02087 }
02088
02089 if (!vms_p) {
02090 vms_p = create_vm_state_from_user(vmu);
02091 }
02092 ret = init_mailstream(vms_p, fold);
02093 if (!vms_p->mailstream) {
02094 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02095 return -1;
02096 }
02097 if (ret == 0) {
02098 ast_mutex_lock(&vms_p->lock);
02099 pgm = mail_newsearchpgm ();
02100 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02101 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02102 pgm->header = hdr;
02103 if (fold != OLD_FOLDER) {
02104 pgm->unseen = 1;
02105 pgm->seen = 0;
02106 }
02107
02108
02109
02110 else {
02111 pgm->unseen = 0;
02112 pgm->seen = 1;
02113 }
02114
02115 if (fold == NEW_FOLDER) {
02116 if (urgent) {
02117 pgm->flagged = 1;
02118 pgm->unflagged = 0;
02119 } else {
02120 pgm->flagged = 0;
02121 pgm->unflagged = 1;
02122 }
02123 }
02124 pgm->undeleted = 1;
02125 pgm->deleted = 0;
02126
02127 vms_p->vmArrayIndex = 0;
02128 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02129 if (fold == 0 && urgent == 0)
02130 vms_p->newmessages = vms_p->vmArrayIndex;
02131 if (fold == 1)
02132 vms_p->oldmessages = vms_p->vmArrayIndex;
02133 if (fold == 0 && urgent == 1)
02134 vms_p->urgentmessages = vms_p->vmArrayIndex;
02135
02136 mail_free_searchpgm(&pgm);
02137 ast_mutex_unlock(&vms_p->lock);
02138 vms_p->updated = 0;
02139 return vms_p->vmArrayIndex;
02140 } else {
02141 ast_mutex_lock(&vms_p->lock);
02142 mail_ping(vms_p->mailstream);
02143 ast_mutex_unlock(&vms_p->lock);
02144 }
02145 return 0;
02146 }
02147
02148 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02149 {
02150
02151 check_quota(vms, vmu->imapfolder);
02152 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02153 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02154 ast_play_and_wait(chan, "vm-mailboxfull");
02155 return -1;
02156 }
02157
02158
02159 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));
02160 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02161 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02162 ast_play_and_wait(chan, "vm-mailboxfull");
02163 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02164 return -1;
02165 }
02166
02167 return 0;
02168 }
02169
02170
02171
02172
02173
02174
02175
02176
02177
02178
02179 static int messagecount(const char *context, const char *mailbox, const char *folder)
02180 {
02181 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02182 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02183 } else {
02184 return __messagecount(context, mailbox, folder);
02185 }
02186 }
02187
02188 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)
02189 {
02190 char *myserveremail = serveremail;
02191 char fn[PATH_MAX];
02192 char introfn[PATH_MAX];
02193 char mailbox[256];
02194 char *stringp;
02195 FILE *p = NULL;
02196 char tmp[80] = "/tmp/astmail-XXXXXX";
02197 long len;
02198 void *buf;
02199 int tempcopy = 0;
02200 STRING str;
02201 int ret;
02202 char *imap_flags = NIL;
02203 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02204 int box = NEW_FOLDER;
02205
02206
02207 if (msgnum < 0) {
02208 if(!imapgreetings) {
02209 return 0;
02210 } else {
02211 box = GREETINGS_FOLDER;
02212 }
02213 }
02214
02215 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02216 return -1;
02217 }
02218
02219
02220 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02221 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02222 imap_flags = "\\FLAGGED";
02223 }
02224
02225
02226 fmt = ast_strdupa(fmt);
02227 stringp = fmt;
02228 strsep(&stringp, "|");
02229
02230 if (!ast_strlen_zero(vmu->serveremail))
02231 myserveremail = vmu->serveremail;
02232
02233 if (msgnum > -1)
02234 make_file(fn, sizeof(fn), dir, msgnum);
02235 else
02236 ast_copy_string (fn, dir, sizeof(fn));
02237
02238 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02239 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02240 *introfn = '\0';
02241 }
02242
02243 if (ast_strlen_zero(vmu->email)) {
02244
02245
02246
02247
02248
02249 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02250 tempcopy = 1;
02251 }
02252
02253 if (!strcmp(fmt, "wav49"))
02254 fmt = "WAV";
02255 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02256
02257
02258
02259 if (!(p = vm_mkftemp(tmp))) {
02260 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02261 if (tempcopy)
02262 *(vmu->email) = '\0';
02263 return -1;
02264 }
02265
02266 if (msgnum < 0 && imapgreetings) {
02267 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02268 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02269 return -1;
02270 }
02271 imap_delete_old_greeting(fn, vms);
02272 }
02273
02274 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02275 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02276 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02277 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02278
02279 len = ftell(p);
02280 rewind(p);
02281 if (!(buf = ast_malloc(len + 1))) {
02282 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02283 fclose(p);
02284 if (tempcopy)
02285 *(vmu->email) = '\0';
02286 return -1;
02287 }
02288 if (fread(buf, len, 1, p) < len) {
02289 if (ferror(p)) {
02290 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02291 return -1;
02292 }
02293 }
02294 ((char *) buf)[len] = '\0';
02295 INIT(&str, mail_string, buf, len);
02296 ret = init_mailstream(vms, box);
02297 if (ret == 0) {
02298 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02299 ast_mutex_lock(&vms->lock);
02300 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02301 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02302 ast_mutex_unlock(&vms->lock);
02303 fclose(p);
02304 unlink(tmp);
02305 ast_free(buf);
02306 } else {
02307 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02308 fclose(p);
02309 unlink(tmp);
02310 ast_free(buf);
02311 return -1;
02312 }
02313 ast_debug(3, "%s stored\n", fn);
02314
02315 if (tempcopy)
02316 *(vmu->email) = '\0';
02317 inprocess_count(vmu->mailbox, vmu->context, -1);
02318 return 0;
02319
02320 }
02321
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02336 {
02337 char tmp[PATH_MAX] = "";
02338 char *mailboxnc;
02339 char *context;
02340 char *mb;
02341 char *cur;
02342 if (newmsgs)
02343 *newmsgs = 0;
02344 if (oldmsgs)
02345 *oldmsgs = 0;
02346 if (urgentmsgs)
02347 *urgentmsgs = 0;
02348
02349 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02350
02351 if (ast_strlen_zero(mailbox_context))
02352 return 0;
02353
02354 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02355 context = strchr(tmp, '@');
02356 if (strchr(mailbox_context, ',')) {
02357 int tmpnew, tmpold, tmpurgent;
02358 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02359 mb = tmp;
02360 while ((cur = strsep(&mb, ", "))) {
02361 if (!ast_strlen_zero(cur)) {
02362 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02363 return -1;
02364 else {
02365 if (newmsgs)
02366 *newmsgs += tmpnew;
02367 if (oldmsgs)
02368 *oldmsgs += tmpold;
02369 if (urgentmsgs)
02370 *urgentmsgs += tmpurgent;
02371 }
02372 }
02373 }
02374 return 0;
02375 }
02376 if (context) {
02377 *context = '\0';
02378 mailboxnc = tmp;
02379 context++;
02380 } else {
02381 context = "default";
02382 mailboxnc = (char *) mailbox_context;
02383 }
02384
02385 if (newmsgs) {
02386 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02387 if (!vmu) {
02388 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02389 return -1;
02390 }
02391 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02392 return -1;
02393 }
02394 }
02395 if (oldmsgs) {
02396 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02397 return -1;
02398 }
02399 }
02400 if (urgentmsgs) {
02401 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02402 return -1;
02403 }
02404 }
02405 return 0;
02406 }
02407
02408
02409
02410
02411
02412
02413
02414
02415
02416
02417
02418 static int has_voicemail(const char *mailbox, const char *folder)
02419 {
02420 char tmp[256], *tmp2, *box, *context;
02421 ast_copy_string(tmp, mailbox, sizeof(tmp));
02422 tmp2 = tmp;
02423 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02424 while ((box = strsep(&tmp2, ",&"))) {
02425 if (!ast_strlen_zero(box)) {
02426 if (has_voicemail(box, folder)) {
02427 return 1;
02428 }
02429 }
02430 }
02431 }
02432 if ((context = strchr(tmp, '@'))) {
02433 *context++ = '\0';
02434 } else {
02435 context = "default";
02436 }
02437 return __messagecount(context, tmp, folder) ? 1 : 0;
02438 }
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450
02451
02452
02453
02454
02455 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)
02456 {
02457 struct vm_state *sendvms = NULL, *destvms = NULL;
02458 char messagestring[10];
02459 if (msgnum >= recip->maxmsg) {
02460 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02461 return -1;
02462 }
02463 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02464 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02465 return -1;
02466 }
02467 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02468 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02469 return -1;
02470 }
02471 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02472 ast_mutex_lock(&sendvms->lock);
02473 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02474 ast_mutex_unlock(&sendvms->lock);
02475 return 0;
02476 }
02477 ast_mutex_unlock(&sendvms->lock);
02478 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02479 return -1;
02480 }
02481
02482 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02483 {
02484 char tmp[256], *t = tmp;
02485 size_t left = sizeof(tmp);
02486
02487 if (box == OLD_FOLDER) {
02488 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02489 } else {
02490 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02491 }
02492
02493 if (box == NEW_FOLDER) {
02494 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02495 } else {
02496 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02497 }
02498
02499
02500 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02501
02502
02503 if (!ast_strlen_zero(authuser))
02504 ast_build_string(&t, &left, "/authuser=%s", authuser);
02505
02506
02507 if (!ast_strlen_zero(imapflags))
02508 ast_build_string(&t, &left, "/%s", imapflags);
02509
02510
02511 #if 1
02512 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02513 #else
02514 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02515 #endif
02516 if (box == NEW_FOLDER || box == OLD_FOLDER)
02517 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02518 else if (box == GREETINGS_FOLDER)
02519 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02520 else {
02521 if (!ast_strlen_zero(imapparentfolder)) {
02522
02523 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02524 } else {
02525 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02526 }
02527 }
02528 }
02529
02530 static int init_mailstream(struct vm_state *vms, int box)
02531 {
02532 MAILSTREAM *stream = NIL;
02533 long debug;
02534 char tmp[256];
02535
02536 if (!vms) {
02537 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02538 return -1;
02539 }
02540 if (option_debug > 2)
02541 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02542 if (vms->mailstream == NIL || !vms->mailstream) {
02543 if (option_debug)
02544 ast_log(LOG_DEBUG, "mailstream not set.\n");
02545 } else {
02546 stream = vms->mailstream;
02547 }
02548
02549 debug = NIL;
02550
02551 if (delimiter == '\0') {
02552 char *cp;
02553 #ifdef USE_SYSTEM_IMAP
02554 #include <imap/linkage.c>
02555 #elif defined(USE_SYSTEM_CCLIENT)
02556 #include <c-client/linkage.c>
02557 #else
02558 #include "linkage.c"
02559 #endif
02560
02561 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02562 ast_mutex_lock(&vms->lock);
02563 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02564 ast_mutex_unlock(&vms->lock);
02565 if (stream == NIL) {
02566 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02567 return -1;
02568 }
02569 get_mailbox_delimiter(stream);
02570
02571 for (cp = vms->imapfolder; *cp; cp++)
02572 if (*cp == '/')
02573 *cp = delimiter;
02574 }
02575
02576 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02577 if (option_debug > 2)
02578 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02579 ast_mutex_lock(&vms->lock);
02580 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02581 ast_mutex_unlock(&vms->lock);
02582 if (vms->mailstream == NIL) {
02583 return -1;
02584 } else {
02585 return 0;
02586 }
02587 }
02588
02589 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02590 {
02591 SEARCHPGM *pgm;
02592 SEARCHHEADER *hdr;
02593 int ret, urgent = 0;
02594
02595
02596 if (box == 11) {
02597 box = NEW_FOLDER;
02598 urgent = 1;
02599 }
02600
02601 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02602 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02603 vms->imapversion = vmu->imapversion;
02604 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02605
02606 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02607 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02608 return -1;
02609 }
02610
02611 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02612
02613
02614 if (box == 0) {
02615 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02616 check_quota(vms, (char *) mbox(vmu, box));
02617 }
02618
02619 ast_mutex_lock(&vms->lock);
02620 pgm = mail_newsearchpgm();
02621
02622
02623 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02624 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02625 pgm->header = hdr;
02626 pgm->deleted = 0;
02627 pgm->undeleted = 1;
02628
02629
02630 if (box == NEW_FOLDER && urgent == 1) {
02631 pgm->unseen = 1;
02632 pgm->seen = 0;
02633 pgm->flagged = 1;
02634 pgm->unflagged = 0;
02635 } else if (box == NEW_FOLDER && urgent == 0) {
02636 pgm->unseen = 1;
02637 pgm->seen = 0;
02638 pgm->flagged = 0;
02639 pgm->unflagged = 1;
02640 } else if (box == OLD_FOLDER) {
02641 pgm->seen = 1;
02642 pgm->unseen = 0;
02643 }
02644
02645 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02646
02647 vms->vmArrayIndex = 0;
02648 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02649 vms->lastmsg = vms->vmArrayIndex - 1;
02650 mail_free_searchpgm(&pgm);
02651
02652
02653
02654
02655 if (box == 0 && !vms->dh_arraysize) {
02656 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02657 }
02658 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02659 ast_mutex_unlock(&vms->lock);
02660 return -1;
02661 }
02662
02663 ast_mutex_unlock(&vms->lock);
02664 return 0;
02665 }
02666
02667 static void write_file(char *filename, char *buffer, unsigned long len)
02668 {
02669 FILE *output;
02670
02671 output = fopen (filename, "w");
02672 if (fwrite(buffer, len, 1, output) != 1) {
02673 if (ferror(output)) {
02674 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02675 }
02676 }
02677 fclose (output);
02678 }
02679
02680 static void update_messages_by_imapuser(const char *user, unsigned long number)
02681 {
02682 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02683
02684 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02685 return;
02686 }
02687
02688 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02689 vms->msgArray[vms->vmArrayIndex++] = number;
02690 }
02691
02692 void mm_searched(MAILSTREAM *stream, unsigned long number)
02693 {
02694 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02695
02696 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02697 return;
02698
02699 update_messages_by_imapuser(user, number);
02700 }
02701
02702 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02703 {
02704 struct ast_variable *var;
02705 struct ast_vm_user *vmu;
02706
02707 vmu = ast_calloc(1, sizeof *vmu);
02708 if (!vmu)
02709 return NULL;
02710 ast_set_flag(vmu, VM_ALLOCED);
02711 populate_defaults(vmu);
02712
02713 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02714 if (var) {
02715 apply_options_full(vmu, var);
02716 ast_variables_destroy(var);
02717 return vmu;
02718 } else {
02719 ast_free(vmu);
02720 return NULL;
02721 }
02722 }
02723
02724
02725
02726 void mm_exists(MAILSTREAM * stream, unsigned long number)
02727 {
02728
02729 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02730 if (number == 0) return;
02731 set_update(stream);
02732 }
02733
02734
02735 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02736 {
02737
02738 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02739 if (number == 0) return;
02740 set_update(stream);
02741 }
02742
02743
02744 void mm_flags(MAILSTREAM * stream, unsigned long number)
02745 {
02746
02747 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02748 if (number == 0) return;
02749 set_update(stream);
02750 }
02751
02752
02753 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02754 {
02755 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02756 mm_log (string, errflg);
02757 }
02758
02759
02760 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02761 {
02762 if (delimiter == '\0') {
02763 delimiter = delim;
02764 }
02765
02766 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02767 if (attributes & LATT_NOINFERIORS)
02768 ast_debug(5, "no inferiors\n");
02769 if (attributes & LATT_NOSELECT)
02770 ast_debug(5, "no select\n");
02771 if (attributes & LATT_MARKED)
02772 ast_debug(5, "marked\n");
02773 if (attributes & LATT_UNMARKED)
02774 ast_debug(5, "unmarked\n");
02775 }
02776
02777
02778 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
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_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02793 {
02794 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02795 if (status->flags & SA_MESSAGES)
02796 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02797 if (status->flags & SA_RECENT)
02798 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02799 if (status->flags & SA_UNSEEN)
02800 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02801 if (status->flags & SA_UIDVALIDITY)
02802 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02803 if (status->flags & SA_UIDNEXT)
02804 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02805 ast_log(AST_LOG_NOTICE, "\n");
02806 }
02807
02808
02809 void mm_log(char *string, long errflg)
02810 {
02811 switch ((short) errflg) {
02812 case NIL:
02813 ast_debug(1, "IMAP Info: %s\n", string);
02814 break;
02815 case PARSE:
02816 case WARN:
02817 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02818 break;
02819 case ERROR:
02820 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02821 break;
02822 }
02823 }
02824
02825
02826 void mm_dlog(char *string)
02827 {
02828 ast_log(AST_LOG_NOTICE, "%s\n", string);
02829 }
02830
02831
02832 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02833 {
02834 struct ast_vm_user *vmu;
02835
02836 ast_debug(4, "Entering callback mm_login\n");
02837
02838 ast_copy_string(user, mb->user, MAILTMPLEN);
02839
02840
02841 if (!ast_strlen_zero(authpassword)) {
02842 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02843 } else {
02844 AST_LIST_TRAVERSE(&users, vmu, list) {
02845 if (!strcasecmp(mb->user, vmu->imapuser)) {
02846 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02847 break;
02848 }
02849 }
02850 if (!vmu) {
02851 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02852 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02853 free_user(vmu);
02854 }
02855 }
02856 }
02857 }
02858
02859
02860 void mm_critical(MAILSTREAM * stream)
02861 {
02862 }
02863
02864
02865 void mm_nocritical(MAILSTREAM * stream)
02866 {
02867 }
02868
02869
02870 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02871 {
02872 kill (getpid (), SIGSTOP);
02873 return NIL;
02874 }
02875
02876
02877 void mm_fatal(char *string)
02878 {
02879 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02880 }
02881
02882
02883 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02884 {
02885 struct vm_state *vms;
02886 char *mailbox = stream->mailbox, *user;
02887 char buf[1024] = "";
02888 unsigned long usage = 0, limit = 0;
02889
02890 while (pquota) {
02891 usage = pquota->usage;
02892 limit = pquota->limit;
02893 pquota = pquota->next;
02894 }
02895
02896 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)))) {
02897 ast_log(AST_LOG_ERROR, "No state found.\n");
02898 return;
02899 }
02900
02901 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02902
02903 vms->quota_usage = usage;
02904 vms->quota_limit = limit;
02905 }
02906
02907 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02908 {
02909 char *start, *eol_pnt;
02910 int taglen;
02911
02912 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02913 return NULL;
02914
02915 taglen = strlen(tag) + 1;
02916 if (taglen < 1)
02917 return NULL;
02918
02919 if (!(start = strstr(header, tag)))
02920 return NULL;
02921
02922
02923 memset(buf, 0, len);
02924
02925 ast_copy_string(buf, start+taglen, len);
02926 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02927 *eol_pnt = '\0';
02928 return buf;
02929 }
02930
02931 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02932 {
02933 char *start, *quote, *eol_pnt;
02934
02935 if (ast_strlen_zero(mailbox))
02936 return NULL;
02937
02938 if (!(start = strstr(mailbox, "/user=")))
02939 return NULL;
02940
02941 ast_copy_string(buf, start+6, len);
02942
02943 if (!(quote = strchr(buf, '\"'))) {
02944 if (!(eol_pnt = strchr(buf, '/')))
02945 eol_pnt = strchr(buf,'}');
02946 *eol_pnt = '\0';
02947 return buf;
02948 } else {
02949 eol_pnt = strchr(buf+1,'\"');
02950 *eol_pnt = '\0';
02951 return buf+1;
02952 }
02953 }
02954
02955 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02956 {
02957 struct vm_state *vms_p;
02958
02959 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02960 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02961 return vms_p;
02962 }
02963 if (option_debug > 4)
02964 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02965 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02966 return NULL;
02967 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02968 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
02969 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02970 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02971 vms_p->mailstream = NIL;
02972 vms_p->imapversion = vmu->imapversion;
02973 if (option_debug > 4)
02974 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
02975 vms_p->updated = 1;
02976
02977 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
02978 init_vm_state(vms_p);
02979 vmstate_insert(vms_p);
02980 return vms_p;
02981 }
02982
02983 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
02984 {
02985 struct vmstate *vlist = NULL;
02986
02987 if (interactive) {
02988 struct vm_state *vms;
02989 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02990 vms = pthread_getspecific(ts_vmstate.key);
02991 return vms;
02992 }
02993
02994 AST_LIST_LOCK(&vmstates);
02995 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02996 if (!vlist->vms) {
02997 ast_debug(3, "error: vms is NULL for %s\n", user);
02998 continue;
02999 }
03000 if (vlist->vms->imapversion != imapversion) {
03001 continue;
03002 }
03003 if (!vlist->vms->imapuser) {
03004 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03005 continue;
03006 }
03007
03008 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03009 AST_LIST_UNLOCK(&vmstates);
03010 return vlist->vms;
03011 }
03012 }
03013 AST_LIST_UNLOCK(&vmstates);
03014
03015 ast_debug(3, "%s not found in vmstates\n", user);
03016
03017 return NULL;
03018 }
03019
03020 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03021 {
03022
03023 struct vmstate *vlist = NULL;
03024 const char *local_context = S_OR(context, "default");
03025
03026 if (interactive) {
03027 struct vm_state *vms;
03028 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03029 vms = pthread_getspecific(ts_vmstate.key);
03030 return vms;
03031 }
03032
03033 AST_LIST_LOCK(&vmstates);
03034 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03035 if (!vlist->vms) {
03036 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03037 continue;
03038 }
03039 if (vlist->vms->imapversion != imapversion) {
03040 continue;
03041 }
03042 if (!vlist->vms->username || !vlist->vms->context) {
03043 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03044 continue;
03045 }
03046
03047 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);
03048
03049 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03050 ast_debug(3, "Found it!\n");
03051 AST_LIST_UNLOCK(&vmstates);
03052 return vlist->vms;
03053 }
03054 }
03055 AST_LIST_UNLOCK(&vmstates);
03056
03057 ast_debug(3, "%s not found in vmstates\n", mailbox);
03058
03059 return NULL;
03060 }
03061
03062 static void vmstate_insert(struct vm_state *vms)
03063 {
03064 struct vmstate *v;
03065 struct vm_state *altvms;
03066
03067
03068
03069
03070 if (vms->interactive == 1) {
03071 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03072 if (altvms) {
03073 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03074 vms->newmessages = altvms->newmessages;
03075 vms->oldmessages = altvms->oldmessages;
03076 vms->vmArrayIndex = altvms->vmArrayIndex;
03077 vms->lastmsg = altvms->lastmsg;
03078 vms->curmsg = altvms->curmsg;
03079
03080 vms->persist_vms = altvms;
03081
03082 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03083 vms->mailstream = altvms->mailstream;
03084 #else
03085 vms->mailstream = NIL;
03086 #endif
03087 }
03088 return;
03089 }
03090
03091 if (!(v = ast_calloc(1, sizeof(*v))))
03092 return;
03093
03094 v->vms = vms;
03095
03096 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03097
03098 AST_LIST_LOCK(&vmstates);
03099 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03100 AST_LIST_UNLOCK(&vmstates);
03101 }
03102
03103 static void vmstate_delete(struct vm_state *vms)
03104 {
03105 struct vmstate *vc = NULL;
03106 struct vm_state *altvms = NULL;
03107
03108
03109
03110 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03111 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03112 altvms->newmessages = vms->newmessages;
03113 altvms->oldmessages = vms->oldmessages;
03114 altvms->updated = 1;
03115 vms->mailstream = mail_close(vms->mailstream);
03116
03117
03118 return;
03119 }
03120
03121 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03122
03123 AST_LIST_LOCK(&vmstates);
03124 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03125 if (vc->vms == vms) {
03126 AST_LIST_REMOVE_CURRENT(list);
03127 break;
03128 }
03129 }
03130 AST_LIST_TRAVERSE_SAFE_END
03131 AST_LIST_UNLOCK(&vmstates);
03132
03133 if (vc) {
03134 ast_mutex_destroy(&vc->vms->lock);
03135 ast_free(vc);
03136 }
03137 else
03138 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03139 }
03140
03141 static void set_update(MAILSTREAM * stream)
03142 {
03143 struct vm_state *vms;
03144 char *mailbox = stream->mailbox, *user;
03145 char buf[1024] = "";
03146
03147 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03148 if (user && option_debug > 2)
03149 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03150 return;
03151 }
03152
03153 ast_debug(3, "User %s mailbox set for update.\n", user);
03154
03155 vms->updated = 1;
03156 }
03157
03158 static void init_vm_state(struct vm_state *vms)
03159 {
03160 int x;
03161 vms->vmArrayIndex = 0;
03162 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03163 vms->msgArray[x] = 0;
03164 }
03165 ast_mutex_init(&vms->lock);
03166 }
03167
03168 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03169 {
03170 char *body_content;
03171 char *body_decoded;
03172 char *fn = is_intro ? vms->introfn : vms->fn;
03173 unsigned long len;
03174 unsigned long newlen;
03175 char filename[256];
03176
03177 if (!body || body == NIL)
03178 return -1;
03179
03180 ast_mutex_lock(&vms->lock);
03181 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03182 ast_mutex_unlock(&vms->lock);
03183 if (body_content != NIL) {
03184 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03185
03186 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03187
03188 if (!newlen) {
03189 return -1;
03190 }
03191 write_file(filename, (char *) body_decoded, newlen);
03192 } else {
03193 ast_debug(5, "Body of message is NULL.\n");
03194 return -1;
03195 }
03196 return 0;
03197 }
03198
03199
03200
03201
03202
03203
03204
03205
03206 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03207 char tmp[50];
03208 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03209 mail_list(stream, tmp, "*");
03210 }
03211
03212
03213
03214
03215
03216
03217
03218
03219 static void check_quota(struct vm_state *vms, char *mailbox) {
03220 ast_mutex_lock(&vms->lock);
03221 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03222 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03223 if (vms && vms->mailstream != NULL) {
03224 imap_getquotaroot(vms->mailstream, mailbox);
03225 } else {
03226 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03227 }
03228 ast_mutex_unlock(&vms->lock);
03229 }
03230
03231 #endif
03232
03233
03234
03235
03236
03237 static int vm_lock_path(const char *path)
03238 {
03239 switch (ast_lock_path(path)) {
03240 case AST_LOCK_TIMEOUT:
03241 return -1;
03242 default:
03243 return 0;
03244 }
03245 }
03246
03247
03248 #ifdef ODBC_STORAGE
03249 struct generic_prepare_struct {
03250 char *sql;
03251 int argc;
03252 char **argv;
03253 };
03254
03255 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03256 {
03257 struct generic_prepare_struct *gps = data;
03258 int res, i;
03259 SQLHSTMT stmt;
03260
03261 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03262 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03263 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03264 return NULL;
03265 }
03266 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03267 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03268 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03269 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03270 return NULL;
03271 }
03272 for (i = 0; i < gps->argc; i++)
03273 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03274
03275 return stmt;
03276 }
03277
03278
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292 static int retrieve_file(char *dir, int msgnum)
03293 {
03294 int x = 0;
03295 int res;
03296 int fd = -1;
03297 size_t fdlen = 0;
03298 void *fdm = MAP_FAILED;
03299 SQLSMALLINT colcount = 0;
03300 SQLHSTMT stmt;
03301 char sql[PATH_MAX];
03302 char fmt[80]="";
03303 char *c;
03304 char coltitle[256];
03305 SQLSMALLINT collen;
03306 SQLSMALLINT datatype;
03307 SQLSMALLINT decimaldigits;
03308 SQLSMALLINT nullable;
03309 SQLULEN colsize;
03310 SQLLEN colsize2;
03311 FILE *f = NULL;
03312 char rowdata[80];
03313 char fn[PATH_MAX];
03314 char full_fn[PATH_MAX];
03315 char msgnums[80];
03316 char *argv[] = { dir, msgnums };
03317 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03318
03319 struct odbc_obj *obj;
03320 obj = ast_odbc_request_obj(odbc_database, 0);
03321 if (obj) {
03322 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03323 c = strchr(fmt, '|');
03324 if (c)
03325 *c = '\0';
03326 if (!strcasecmp(fmt, "wav49"))
03327 strcpy(fmt, "WAV");
03328 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03329 if (msgnum > -1)
03330 make_file(fn, sizeof(fn), dir, msgnum);
03331 else
03332 ast_copy_string(fn, dir, sizeof(fn));
03333
03334
03335 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03336
03337 if (!(f = fopen(full_fn, "w+"))) {
03338 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03339 goto yuck;
03340 }
03341
03342 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03343 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03344 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03345 if (!stmt) {
03346 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03347 ast_odbc_release_obj(obj);
03348 goto yuck;
03349 }
03350 res = SQLFetch(stmt);
03351 if (res == SQL_NO_DATA) {
03352 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03353 ast_odbc_release_obj(obj);
03354 goto yuck;
03355 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03356 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03357 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03358 ast_odbc_release_obj(obj);
03359 goto yuck;
03360 }
03361 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03362 if (fd < 0) {
03363 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03364 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03365 ast_odbc_release_obj(obj);
03366 goto yuck;
03367 }
03368 res = SQLNumResultCols(stmt, &colcount);
03369 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03370 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03371 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03372 ast_odbc_release_obj(obj);
03373 goto yuck;
03374 }
03375 if (f)
03376 fprintf(f, "[message]\n");
03377 for (x = 0; x < colcount; x++) {
03378 rowdata[0] = '\0';
03379 colsize = 0;
03380 collen = sizeof(coltitle);
03381 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03382 &datatype, &colsize, &decimaldigits, &nullable);
03383 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03384 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03385 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03386 ast_odbc_release_obj(obj);
03387 goto yuck;
03388 }
03389 if (!strcasecmp(coltitle, "recording")) {
03390 off_t offset;
03391 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03392 fdlen = colsize2;
03393 if (fd > -1) {
03394 char tmp[1]="";
03395 lseek(fd, fdlen - 1, SEEK_SET);
03396 if (write(fd, tmp, 1) != 1) {
03397 close(fd);
03398 fd = -1;
03399 continue;
03400 }
03401
03402 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03403 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03404 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03405 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03406 ast_odbc_release_obj(obj);
03407 goto yuck;
03408 } else {
03409 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03410 munmap(fdm, CHUNKSIZE);
03411 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03412 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03413 unlink(full_fn);
03414 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03415 ast_odbc_release_obj(obj);
03416 goto yuck;
03417 }
03418 }
03419 }
03420 if (truncate(full_fn, fdlen) < 0) {
03421 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03422 }
03423 }
03424 } else {
03425 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03426 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03427 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03428 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03429 ast_odbc_release_obj(obj);
03430 goto yuck;
03431 }
03432 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03433 fprintf(f, "%s=%s\n", coltitle, rowdata);
03434 }
03435 }
03436 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03437 ast_odbc_release_obj(obj);
03438 } else
03439 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03440 yuck:
03441 if (f)
03442 fclose(f);
03443 if (fd > -1)
03444 close(fd);
03445 return x - 1;
03446 }
03447
03448
03449
03450
03451
03452
03453
03454
03455
03456
03457
03458
03459 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03460 {
03461 int x = 0;
03462 int res;
03463 SQLHSTMT stmt;
03464 char sql[PATH_MAX];
03465 char rowdata[20];
03466 char *argv[] = { dir };
03467 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03468
03469 struct odbc_obj *obj;
03470 obj = ast_odbc_request_obj(odbc_database, 0);
03471 if (obj) {
03472 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03473
03474 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03475 if (!stmt) {
03476 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03477 ast_odbc_release_obj(obj);
03478 goto yuck;
03479 }
03480 res = SQLFetch(stmt);
03481 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03482 if (res == SQL_NO_DATA) {
03483 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03484 } else {
03485 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03486 }
03487
03488 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03489 ast_odbc_release_obj(obj);
03490 goto yuck;
03491 }
03492 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03493 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03494 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03495 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03496 ast_odbc_release_obj(obj);
03497 goto yuck;
03498 }
03499 if (sscanf(rowdata, "%30d", &x) != 1)
03500 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03501 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03502 ast_odbc_release_obj(obj);
03503 return x;
03504 } else
03505 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03506 yuck:
03507 return x - 1;
03508 }
03509
03510
03511
03512
03513
03514
03515
03516
03517
03518
03519 static int message_exists(char *dir, int msgnum)
03520 {
03521 int x = 0;
03522 int res;
03523 SQLHSTMT stmt;
03524 char sql[PATH_MAX];
03525 char rowdata[20];
03526 char msgnums[20];
03527 char *argv[] = { dir, msgnums };
03528 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03529
03530 struct odbc_obj *obj;
03531 obj = ast_odbc_request_obj(odbc_database, 0);
03532 if (obj) {
03533 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03534 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03535 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03536 if (!stmt) {
03537 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03538 ast_odbc_release_obj(obj);
03539 goto yuck;
03540 }
03541 res = SQLFetch(stmt);
03542 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03543 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03544 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03545 ast_odbc_release_obj(obj);
03546 goto yuck;
03547 }
03548 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03549 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03550 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03551 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03552 ast_odbc_release_obj(obj);
03553 goto yuck;
03554 }
03555 if (sscanf(rowdata, "%30d", &x) != 1)
03556 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03557 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03558 ast_odbc_release_obj(obj);
03559 } else
03560 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03561 yuck:
03562 return x;
03563 }
03564
03565
03566
03567
03568
03569
03570
03571
03572
03573
03574 static int count_messages(struct ast_vm_user *vmu, char *dir)
03575 {
03576 int x = 0;
03577 int res;
03578 SQLHSTMT stmt;
03579 char sql[PATH_MAX];
03580 char rowdata[20];
03581 char *argv[] = { dir };
03582 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03583
03584 struct odbc_obj *obj;
03585 obj = ast_odbc_request_obj(odbc_database, 0);
03586 if (obj) {
03587 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03588 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03589 if (!stmt) {
03590 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03591 ast_odbc_release_obj(obj);
03592 goto yuck;
03593 }
03594 res = SQLFetch(stmt);
03595 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03596 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03597 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03598 ast_odbc_release_obj(obj);
03599 goto yuck;
03600 }
03601 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03602 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03603 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03604 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03605 ast_odbc_release_obj(obj);
03606 goto yuck;
03607 }
03608 if (sscanf(rowdata, "%30d", &x) != 1)
03609 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03610 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03611 ast_odbc_release_obj(obj);
03612 return x;
03613 } else
03614 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03615 yuck:
03616 return x - 1;
03617
03618 }
03619
03620
03621
03622
03623
03624
03625
03626
03627
03628
03629
03630 static void delete_file(const char *sdir, int smsg)
03631 {
03632 SQLHSTMT stmt;
03633 char sql[PATH_MAX];
03634 char msgnums[20];
03635 char *argv[] = { NULL, msgnums };
03636 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03637 struct odbc_obj *obj;
03638
03639 argv[0] = ast_strdupa(sdir);
03640
03641 obj = ast_odbc_request_obj(odbc_database, 0);
03642 if (obj) {
03643 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03644 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03645 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03646 if (!stmt)
03647 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03648 else
03649 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03650 ast_odbc_release_obj(obj);
03651 } else
03652 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03653 return;
03654 }
03655
03656
03657
03658
03659
03660
03661
03662
03663
03664
03665
03666
03667 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03668 {
03669 SQLHSTMT stmt;
03670 char sql[512];
03671 char msgnums[20];
03672 char msgnumd[20];
03673 struct odbc_obj *obj;
03674 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03675 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03676
03677 delete_file(ddir, dmsg);
03678 obj = ast_odbc_request_obj(odbc_database, 0);
03679 if (obj) {
03680 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03681 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03682 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);
03683 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03684 if (!stmt)
03685 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03686 else
03687 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03688 ast_odbc_release_obj(obj);
03689 } else
03690 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03691 return;
03692 }
03693
03694 struct insert_data {
03695 char *sql;
03696 const char *dir;
03697 const char *msgnums;
03698 void *data;
03699 SQLLEN datalen;
03700 SQLLEN indlen;
03701 const char *context;
03702 const char *macrocontext;
03703 const char *callerid;
03704 const char *origtime;
03705 const char *duration;
03706 const char *mailboxuser;
03707 const char *mailboxcontext;
03708 const char *category;
03709 const char *flag;
03710 };
03711
03712 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03713 {
03714 struct insert_data *data = vdata;
03715 int res;
03716 SQLHSTMT stmt;
03717
03718 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03719 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03720 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03721 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03722 return NULL;
03723 }
03724
03725 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03726 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03727 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03728 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03729 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03730 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03731 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03732 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03733 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03734 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03735 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03736 if (!ast_strlen_zero(data->category)) {
03737 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03738 }
03739 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03740 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03741 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03742 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03743 return NULL;
03744 }
03745
03746 return stmt;
03747 }
03748
03749
03750
03751
03752
03753
03754
03755
03756
03757
03758
03759
03760
03761
03762 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03763 {
03764 int res = 0;
03765 int fd = -1;
03766 void *fdm = MAP_FAILED;
03767 size_t fdlen = -1;
03768 SQLHSTMT stmt;
03769 char sql[PATH_MAX];
03770 char msgnums[20];
03771 char fn[PATH_MAX];
03772 char full_fn[PATH_MAX];
03773 char fmt[80]="";
03774 char *c;
03775 struct ast_config *cfg = NULL;
03776 struct odbc_obj *obj;
03777 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03778 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03779 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03780
03781 delete_file(dir, msgnum);
03782 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03783 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03784 return -1;
03785 }
03786
03787 do {
03788 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03789 c = strchr(fmt, '|');
03790 if (c)
03791 *c = '\0';
03792 if (!strcasecmp(fmt, "wav49"))
03793 strcpy(fmt, "WAV");
03794 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03795 if (msgnum > -1)
03796 make_file(fn, sizeof(fn), dir, msgnum);
03797 else
03798 ast_copy_string(fn, dir, sizeof(fn));
03799 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03800 cfg = ast_config_load(full_fn, config_flags);
03801 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03802 fd = open(full_fn, O_RDWR);
03803 if (fd < 0) {
03804 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03805 res = -1;
03806 break;
03807 }
03808 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03809 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03810 idata.context = "";
03811 }
03812 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03813 idata.macrocontext = "";
03814 }
03815 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03816 idata.callerid = "";
03817 }
03818 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03819 idata.origtime = "";
03820 }
03821 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03822 idata.duration = "";
03823 }
03824 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03825 idata.category = "";
03826 }
03827 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03828 idata.flag = "";
03829 }
03830 }
03831 fdlen = lseek(fd, 0, SEEK_END);
03832 lseek(fd, 0, SEEK_SET);
03833 printf("Length is %zd\n", fdlen);
03834 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03835 if (fdm == MAP_FAILED) {
03836 ast_log(AST_LOG_WARNING, "Memory map failed!\n");
03837 res = -1;
03838 break;
03839 }
03840 idata.data = fdm;
03841 idata.datalen = idata.indlen = fdlen;
03842
03843 if (!ast_strlen_zero(idata.category))
03844 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03845 else
03846 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03847
03848 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03849 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03850 } else {
03851 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03852 res = -1;
03853 }
03854 } while (0);
03855 if (obj) {
03856 ast_odbc_release_obj(obj);
03857 }
03858 if (cfg)
03859 ast_config_destroy(cfg);
03860 if (fdm != MAP_FAILED)
03861 munmap(fdm, fdlen);
03862 if (fd > -1)
03863 close(fd);
03864 return res;
03865 }
03866
03867
03868
03869
03870
03871
03872
03873
03874
03875
03876
03877
03878
03879
03880 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03881 {
03882 SQLHSTMT stmt;
03883 char sql[PATH_MAX];
03884 char msgnums[20];
03885 char msgnumd[20];
03886 struct odbc_obj *obj;
03887 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03888 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03889
03890 delete_file(ddir, dmsg);
03891 obj = ast_odbc_request_obj(odbc_database, 0);
03892 if (obj) {
03893 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03894 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03895 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03896 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03897 if (!stmt)
03898 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03899 else
03900 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03901 ast_odbc_release_obj(obj);
03902 } else
03903 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03904 return;
03905 }
03906
03907
03908
03909
03910
03911
03912
03913
03914
03915
03916
03917
03918 static int remove_file(char *dir, int msgnum)
03919 {
03920 char fn[PATH_MAX];
03921 char full_fn[PATH_MAX];
03922 char msgnums[80];
03923
03924 if (msgnum > -1) {
03925 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03926 make_file(fn, sizeof(fn), dir, msgnum);
03927 } else
03928 ast_copy_string(fn, dir, sizeof(fn));
03929 ast_filedelete(fn, NULL);
03930 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03931 unlink(full_fn);
03932 return 0;
03933 }
03934 #else
03935 #ifndef IMAP_STORAGE
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945 static int count_messages(struct ast_vm_user *vmu, char *dir)
03946 {
03947
03948 int vmcount = 0;
03949 DIR *vmdir = NULL;
03950 struct dirent *vment = NULL;
03951
03952 if (vm_lock_path(dir))
03953 return ERROR_LOCK_PATH;
03954
03955 if ((vmdir = opendir(dir))) {
03956 while ((vment = readdir(vmdir))) {
03957 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03958 vmcount++;
03959 }
03960 }
03961 closedir(vmdir);
03962 }
03963 ast_unlock_path(dir);
03964
03965 return vmcount;
03966 }
03967
03968
03969
03970
03971
03972
03973
03974
03975 static void rename_file(char *sfn, char *dfn)
03976 {
03977 char stxt[PATH_MAX];
03978 char dtxt[PATH_MAX];
03979 ast_filerename(sfn, dfn, NULL);
03980 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
03981 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
03982 if (ast_check_realtime("voicemail_data")) {
03983 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
03984 }
03985 rename(stxt, dtxt);
03986 }
03987
03988
03989
03990
03991
03992
03993
03994
03995
03996
03997
03998
03999 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04000 {
04001 int x;
04002 unsigned char map[MAXMSGLIMIT] = "";
04003 DIR *msgdir;
04004 struct dirent *msgdirent;
04005 int msgdirint;
04006 char extension[4];
04007 int stopcount = 0;
04008
04009
04010
04011
04012
04013 if (!(msgdir = opendir(dir))) {
04014 return -1;
04015 }
04016
04017 while ((msgdirent = readdir(msgdir))) {
04018 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04019 map[msgdirint] = 1;
04020 stopcount++;
04021 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04022 }
04023 }
04024 closedir(msgdir);
04025
04026 for (x = 0; x < vmu->maxmsg; x++) {
04027 if (map[x] == 1) {
04028 stopcount--;
04029 } else if (map[x] == 0 && !stopcount) {
04030 break;
04031 }
04032 }
04033
04034 return x - 1;
04035 }
04036
04037 #endif
04038 #endif
04039 #ifndef IMAP_STORAGE
04040
04041
04042
04043
04044
04045
04046
04047
04048
04049
04050 static int copy(char *infile, char *outfile)
04051 {
04052 int ifd;
04053 int ofd;
04054 int res;
04055 int len;
04056 char buf[4096];
04057
04058 #ifdef HARDLINK_WHEN_POSSIBLE
04059
04060 if (link(infile, outfile)) {
04061 #endif
04062 if ((ifd = open(infile, O_RDONLY)) < 0) {
04063 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04064 return -1;
04065 }
04066 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04067 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04068 close(ifd);
04069 return -1;
04070 }
04071 do {
04072 len = read(ifd, buf, sizeof(buf));
04073 if (len < 0) {
04074 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04075 close(ifd);
04076 close(ofd);
04077 unlink(outfile);
04078 }
04079 if (len) {
04080 res = write(ofd, buf, len);
04081 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04082 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04083 close(ifd);
04084 close(ofd);
04085 unlink(outfile);
04086 }
04087 }
04088 } while (len);
04089 close(ifd);
04090 close(ofd);
04091 return 0;
04092 #ifdef HARDLINK_WHEN_POSSIBLE
04093 } else {
04094
04095 return 0;
04096 }
04097 #endif
04098 }
04099
04100
04101
04102
04103
04104
04105
04106
04107
04108
04109 static void copy_plain_file(char *frompath, char *topath)
04110 {
04111 char frompath2[PATH_MAX], topath2[PATH_MAX];
04112 struct ast_variable *tmp,*var = NULL;
04113 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04114 ast_filecopy(frompath, topath, NULL);
04115 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04116 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04117 if (ast_check_realtime("voicemail_data")) {
04118 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04119
04120 for (tmp = var; tmp; tmp = tmp->next) {
04121 if (!strcasecmp(tmp->name, "origmailbox")) {
04122 origmailbox = tmp->value;
04123 } else if (!strcasecmp(tmp->name, "context")) {
04124 context = tmp->value;
04125 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04126 macrocontext = tmp->value;
04127 } else if (!strcasecmp(tmp->name, "exten")) {
04128 exten = tmp->value;
04129 } else if (!strcasecmp(tmp->name, "priority")) {
04130 priority = tmp->value;
04131 } else if (!strcasecmp(tmp->name, "callerchan")) {
04132 callerchan = tmp->value;
04133 } else if (!strcasecmp(tmp->name, "callerid")) {
04134 callerid = tmp->value;
04135 } else if (!strcasecmp(tmp->name, "origdate")) {
04136 origdate = tmp->value;
04137 } else if (!strcasecmp(tmp->name, "origtime")) {
04138 origtime = tmp->value;
04139 } else if (!strcasecmp(tmp->name, "category")) {
04140 category = tmp->value;
04141 } else if (!strcasecmp(tmp->name, "duration")) {
04142 duration = tmp->value;
04143 }
04144 }
04145 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);
04146 }
04147 copy(frompath2, topath2);
04148 ast_variables_destroy(var);
04149 }
04150 #endif
04151
04152
04153
04154
04155
04156
04157
04158
04159
04160 static int vm_delete(char *file)
04161 {
04162 char *txt;
04163 int txtsize = 0;
04164
04165 txtsize = (strlen(file) + 5)*sizeof(char);
04166 txt = alloca(txtsize);
04167
04168
04169
04170 if (ast_check_realtime("voicemail_data")) {
04171 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04172 }
04173 snprintf(txt, txtsize, "%s.txt", file);
04174 unlink(txt);
04175 return ast_filedelete(file, NULL);
04176 }
04177
04178
04179
04180
04181 static int inbuf(struct baseio *bio, FILE *fi)
04182 {
04183 int l;
04184
04185 if (bio->ateof)
04186 return 0;
04187
04188 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04189 if (ferror(fi))
04190 return -1;
04191
04192 bio->ateof = 1;
04193 return 0;
04194 }
04195
04196 bio->iolen = l;
04197 bio->iocp = 0;
04198
04199 return 1;
04200 }
04201
04202
04203
04204
04205 static int inchar(struct baseio *bio, FILE *fi)
04206 {
04207 if (bio->iocp>=bio->iolen) {
04208 if (!inbuf(bio, fi))
04209 return EOF;
04210 }
04211
04212 return bio->iobuf[bio->iocp++];
04213 }
04214
04215
04216
04217
04218 static int ochar(struct baseio *bio, int c, FILE *so)
04219 {
04220 if (bio->linelength >= BASELINELEN) {
04221 if (fputs(ENDL, so) == EOF) {
04222 return -1;
04223 }
04224
04225 bio->linelength = 0;
04226 }
04227
04228 if (putc(((unsigned char) c), so) == EOF) {
04229 return -1;
04230 }
04231
04232 bio->linelength++;
04233
04234 return 1;
04235 }
04236
04237
04238
04239
04240
04241
04242
04243
04244
04245
04246 static int base_encode(char *filename, FILE *so)
04247 {
04248 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04249 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04250 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04251 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04252 int i, hiteof = 0;
04253 FILE *fi;
04254 struct baseio bio;
04255
04256 memset(&bio, 0, sizeof(bio));
04257 bio.iocp = BASEMAXINLINE;
04258
04259 if (!(fi = fopen(filename, "rb"))) {
04260 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04261 return -1;
04262 }
04263
04264 while (!hiteof){
04265 unsigned char igroup[3], ogroup[4];
04266 int c, n;
04267
04268 memset(igroup, 0, sizeof(igroup));
04269
04270 for (n = 0; n < 3; n++) {
04271 if ((c = inchar(&bio, fi)) == EOF) {
04272 hiteof = 1;
04273 break;
04274 }
04275
04276 igroup[n] = (unsigned char) c;
04277 }
04278
04279 if (n > 0) {
04280 ogroup[0]= dtable[igroup[0] >> 2];
04281 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04282 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04283 ogroup[3]= dtable[igroup[2] & 0x3F];
04284
04285 if (n < 3) {
04286 ogroup[3] = '=';
04287
04288 if (n < 2)
04289 ogroup[2] = '=';
04290 }
04291
04292 for (i = 0; i < 4; i++)
04293 ochar(&bio, ogroup[i], so);
04294 }
04295 }
04296
04297 fclose(fi);
04298
04299 if (fputs(ENDL, so) == EOF) {
04300 return 0;
04301 }
04302
04303 return 1;
04304 }
04305
04306 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)
04307 {
04308 char callerid[256];
04309 char num[12];
04310 char fromdir[256], fromfile[256];
04311 struct ast_config *msg_cfg;
04312 const char *origcallerid, *origtime;
04313 char origcidname[80], origcidnum[80], origdate[80];
04314 int inttime;
04315 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04316
04317
04318 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04319 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04320 snprintf(num, sizeof(num), "%d", msgnum);
04321 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04322 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04323 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04324 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04325 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04326 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04327 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04328 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04329 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04330 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04331
04332
04333 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04334 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04335 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04336 strcat(fromfile, ".txt");
04337 }
04338 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04339 if (option_debug > 0) {
04340 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04341 }
04342 return;
04343 }
04344
04345 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04346 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04347 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04348 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04349 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04350 }
04351
04352 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04353 struct timeval tv = { inttime, };
04354 struct ast_tm tm;
04355 ast_localtime(&tv, &tm, NULL);
04356 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04357 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04358 }
04359 ast_config_destroy(msg_cfg);
04360 }
04361
04362
04363
04364
04365
04366
04367
04368
04369
04370 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04371 {
04372 const char *ptr;
04373
04374
04375 ast_str_set(buf, maxlen, "\"");
04376 for (ptr = from; *ptr; ptr++) {
04377 if (*ptr == '"' || *ptr == '\\') {
04378 ast_str_append(buf, maxlen, "\\%c", *ptr);
04379 } else {
04380 ast_str_append(buf, maxlen, "%c", *ptr);
04381 }
04382 }
04383 ast_str_append(buf, maxlen, "\"");
04384
04385 return ast_str_buffer(*buf);
04386 }
04387
04388
04389
04390
04391
04392 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04393 {
04394 const struct vm_zone *z = NULL;
04395 struct timeval t = ast_tvnow();
04396
04397
04398 if (!ast_strlen_zero(vmu->zonetag)) {
04399
04400 AST_LIST_LOCK(&zones);
04401 AST_LIST_TRAVERSE(&zones, z, list) {
04402 if (!strcmp(z->name, vmu->zonetag))
04403 break;
04404 }
04405 AST_LIST_UNLOCK(&zones);
04406 }
04407 ast_localtime(&t, tm, z ? z->timezone : NULL);
04408 return tm;
04409 }
04410
04411
04412
04413
04414
04415 static int check_mime(const char *str)
04416 {
04417 for (; *str; str++) {
04418 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04419 return 1;
04420 }
04421 }
04422 return 0;
04423 }
04424
04425
04426
04427
04428
04429
04430
04431
04432
04433
04434
04435
04436
04437
04438
04439
04440
04441
04442 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04443 {
04444 struct ast_str *tmp = ast_str_alloca(80);
04445 int first_section = 1;
04446
04447 ast_str_reset(*end);
04448 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04449 for (; *start; start++) {
04450 int need_encoding = 0;
04451 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04452 need_encoding = 1;
04453 }
04454 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04455 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04456 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04457 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04458
04459 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04460 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04461 first_section = 0;
04462 }
04463 if (need_encoding && *start == ' ') {
04464 ast_str_append(&tmp, -1, "_");
04465 } else if (need_encoding) {
04466 ast_str_append(&tmp, -1, "=%hhX", *start);
04467 } else {
04468 ast_str_append(&tmp, -1, "%c", *start);
04469 }
04470 }
04471 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04472 return ast_str_buffer(*end);
04473 }
04474
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484
04485
04486
04487
04488
04489
04490
04491
04492
04493
04494
04495
04496
04497
04498 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)
04499 {
04500 char date[256];
04501 char host[MAXHOSTNAMELEN] = "";
04502 char who[256];
04503 char bound[256];
04504 char dur[256];
04505 struct ast_tm tm;
04506 char enc_cidnum[256] = "", enc_cidname[256] = "";
04507 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04508 char *greeting_attachment;
04509 char filename[256];
04510
04511 if (!str1 || !str2) {
04512 ast_free(str1);
04513 ast_free(str2);
04514 return;
04515 }
04516
04517 if (cidnum) {
04518 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04519 }
04520 if (cidname) {
04521 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04522 }
04523 gethostname(host, sizeof(host) - 1);
04524
04525 if (strchr(srcemail, '@')) {
04526 ast_copy_string(who, srcemail, sizeof(who));
04527 } else {
04528 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04529 }
04530
04531 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04532 if (greeting_attachment) {
04533 *greeting_attachment++ = '\0';
04534 }
04535
04536 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04537 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04538 fprintf(p, "Date: %s" ENDL, date);
04539
04540
04541 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04542
04543 if (!ast_strlen_zero(fromstring)) {
04544 struct ast_channel *ast;
04545 if ((ast = ast_dummy_channel_alloc())) {
04546 char *ptr;
04547 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04548 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04549
04550 if (check_mime(ast_str_buffer(str1))) {
04551 int first_line = 1;
04552 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04553 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04554 *ptr = '\0';
04555 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04556 first_line = 0;
04557
04558 ast_str_set(&str2, 0, "%s", ptr + 1);
04559 }
04560 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04561 } else {
04562 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04563 }
04564 ast = ast_channel_unref(ast);
04565 } else {
04566 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04567 }
04568 } else {
04569 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04570 }
04571
04572 if (check_mime(vmu->fullname)) {
04573 int first_line = 1;
04574 char *ptr;
04575 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04576 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04577 *ptr = '\0';
04578 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04579 first_line = 0;
04580
04581 ast_str_set(&str2, 0, "%s", ptr + 1);
04582 }
04583 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04584 } else {
04585 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04586 }
04587
04588 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04589 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04590 struct ast_channel *ast;
04591 if ((ast = ast_dummy_channel_alloc())) {
04592 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04593 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04594 if (check_mime(ast_str_buffer(str1))) {
04595 int first_line = 1;
04596 char *ptr;
04597 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04598 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04599 *ptr = '\0';
04600 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04601 first_line = 0;
04602
04603 ast_str_set(&str2, 0, "%s", ptr + 1);
04604 }
04605 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04606 } else {
04607 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04608 }
04609 ast = ast_channel_unref(ast);
04610 } else {
04611 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04612 }
04613 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04614 if (ast_strlen_zero(flag)) {
04615 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04616 } else {
04617 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04618 }
04619 } else {
04620 if (ast_strlen_zero(flag)) {
04621 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04622 } else {
04623 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04624 }
04625 }
04626
04627 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04628 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04629 if (imap) {
04630
04631 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04632
04633 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04634 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04635 #ifdef IMAP_STORAGE
04636 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04637 #else
04638 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04639 #endif
04640
04641 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04642 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04643 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04644 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04645 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04646 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04647 if (!ast_strlen_zero(category)) {
04648 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04649 } else {
04650 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04651 }
04652 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04653 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04654 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04655 }
04656 if (!ast_strlen_zero(cidnum)) {
04657 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04658 }
04659 if (!ast_strlen_zero(cidname)) {
04660 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04661 }
04662 fprintf(p, "MIME-Version: 1.0" ENDL);
04663 if (attach_user_voicemail) {
04664
04665 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04666 (int) getpid(), (unsigned int) ast_random());
04667
04668 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04669 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04670 fprintf(p, "--%s" ENDL, bound);
04671 }
04672 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04673 if (emailbody || vmu->emailbody) {
04674 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04675 struct ast_channel *ast;
04676 if ((ast = ast_dummy_channel_alloc())) {
04677 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04678 ast_str_substitute_variables(&str1, 0, ast, e_body);
04679 #ifdef IMAP_STORAGE
04680 {
04681
04682 char *line = ast_str_buffer(str1), *next;
04683 do {
04684
04685 if ((next = strchr(line, '\n'))) {
04686 *next++ = '\0';
04687 }
04688 fprintf(p, "%s" ENDL, line);
04689 line = next;
04690 } while (!ast_strlen_zero(line));
04691 }
04692 #else
04693 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04694 #endif
04695 ast = ast_channel_unref(ast);
04696 } else {
04697 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04698 }
04699 } else if (msgnum > -1) {
04700 if (strcmp(vmu->mailbox, mailbox)) {
04701
04702 struct ast_config *msg_cfg;
04703 const char *v;
04704 int inttime;
04705 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04706 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04707
04708 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04709 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04710 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04711 strcat(fromfile, ".txt");
04712 }
04713 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04714 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04715 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04716 }
04717
04718
04719
04720 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04721 struct timeval tv = { inttime, };
04722 struct ast_tm tm;
04723 ast_localtime(&tv, &tm, NULL);
04724 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04725 }
04726 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04727 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04728 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04729 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04730 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04731 date, origcallerid, origdate);
04732 ast_config_destroy(msg_cfg);
04733 } else {
04734 goto plain_message;
04735 }
04736 } else {
04737 plain_message:
04738 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04739 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04740 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04741 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04742 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04743 }
04744 } else {
04745 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04746 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04747 }
04748
04749 if (imap || attach_user_voicemail) {
04750 if (!ast_strlen_zero(attach2)) {
04751 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04752 ast_debug(5, "creating second attachment filename %s\n", filename);
04753 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04754 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04755 ast_debug(5, "creating attachment filename %s\n", filename);
04756 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04757 } else {
04758 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04759 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04760 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04761 }
04762 }
04763 ast_free(str1);
04764 ast_free(str2);
04765 }
04766
04767 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)
04768 {
04769 char tmpdir[256], newtmp[256];
04770 char fname[256];
04771 char tmpcmd[256];
04772 int tmpfd = -1;
04773 int soxstatus = 0;
04774
04775
04776 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04777
04778 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04779 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04780 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04781 tmpfd = mkstemp(newtmp);
04782 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04783 ast_debug(3, "newtmp: %s\n", newtmp);
04784 if (tmpfd > -1) {
04785 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04786 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04787 attach = newtmp;
04788 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04789 } else {
04790 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04791 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04792 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04793 }
04794 }
04795 }
04796 fprintf(p, "--%s" ENDL, bound);
04797 if (msgnum > -1)
04798 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04799 else
04800 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04801 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04802 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04803 if (msgnum > -1)
04804 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04805 else
04806 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04807 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04808 base_encode(fname, p);
04809 if (last)
04810 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04811 if (tmpfd > -1) {
04812 if (soxstatus == 0) {
04813 unlink(fname);
04814 }
04815 close(tmpfd);
04816 unlink(newtmp);
04817 }
04818 return 0;
04819 }
04820
04821 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)
04822 {
04823 FILE *p = NULL;
04824 char tmp[80] = "/tmp/astmail-XXXXXX";
04825 char tmp2[256];
04826 char *stringp;
04827
04828 if (vmu && ast_strlen_zero(vmu->email)) {
04829 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04830 return(0);
04831 }
04832
04833
04834 format = ast_strdupa(format);
04835 stringp = format;
04836 strsep(&stringp, "|");
04837
04838 if (!strcmp(format, "wav49"))
04839 format = "WAV";
04840 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));
04841
04842
04843 if ((p = vm_mkftemp(tmp)) == NULL) {
04844 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04845 return -1;
04846 } else {
04847 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04848 fclose(p);
04849 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04850 ast_safe_system(tmp2);
04851 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04852 }
04853 return 0;
04854 }
04855
04856 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)
04857 {
04858 char enc_cidnum[256], enc_cidname[256];
04859 char date[256];
04860 char host[MAXHOSTNAMELEN] = "";
04861 char who[256];
04862 char dur[PATH_MAX];
04863 char tmp[80] = "/tmp/astmail-XXXXXX";
04864 char tmp2[PATH_MAX];
04865 struct ast_tm tm;
04866 FILE *p;
04867 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04868
04869 if (!str1 || !str2) {
04870 ast_free(str1);
04871 ast_free(str2);
04872 return -1;
04873 }
04874
04875 if (cidnum) {
04876 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04877 }
04878 if (cidname) {
04879 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04880 }
04881
04882 if ((p = vm_mkftemp(tmp)) == NULL) {
04883 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04884 ast_free(str1);
04885 ast_free(str2);
04886 return -1;
04887 }
04888 gethostname(host, sizeof(host)-1);
04889 if (strchr(srcemail, '@')) {
04890 ast_copy_string(who, srcemail, sizeof(who));
04891 } else {
04892 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04893 }
04894 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04895 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04896 fprintf(p, "Date: %s\n", date);
04897
04898
04899 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04900
04901 if (!ast_strlen_zero(pagerfromstring)) {
04902 struct ast_channel *ast;
04903 if ((ast = ast_dummy_channel_alloc())) {
04904 char *ptr;
04905 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04906 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04907
04908 if (check_mime(ast_str_buffer(str1))) {
04909 int first_line = 1;
04910 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04911 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04912 *ptr = '\0';
04913 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04914 first_line = 0;
04915
04916 ast_str_set(&str2, 0, "%s", ptr + 1);
04917 }
04918 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04919 } else {
04920 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04921 }
04922 ast = ast_channel_unref(ast);
04923 } else {
04924 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04925 }
04926 } else {
04927 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04928 }
04929
04930 if (check_mime(vmu->fullname)) {
04931 int first_line = 1;
04932 char *ptr;
04933 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04934 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04935 *ptr = '\0';
04936 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04937 first_line = 0;
04938
04939 ast_str_set(&str2, 0, "%s", ptr + 1);
04940 }
04941 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04942 } else {
04943 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04944 }
04945
04946 if (!ast_strlen_zero(pagersubject)) {
04947 struct ast_channel *ast;
04948 if ((ast = ast_dummy_channel_alloc())) {
04949 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04950 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04951 if (check_mime(ast_str_buffer(str1))) {
04952 int first_line = 1;
04953 char *ptr;
04954 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04955 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04956 *ptr = '\0';
04957 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04958 first_line = 0;
04959
04960 ast_str_set(&str2, 0, "%s", ptr + 1);
04961 }
04962 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04963 } else {
04964 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04965 }
04966 ast = ast_channel_unref(ast);
04967 } else {
04968 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04969 }
04970 } else {
04971 if (ast_strlen_zero(flag)) {
04972 fprintf(p, "Subject: New VM\n\n");
04973 } else {
04974 fprintf(p, "Subject: New %s VM\n\n", flag);
04975 }
04976 }
04977
04978 if (pagerbody) {
04979 struct ast_channel *ast;
04980 if ((ast = ast_dummy_channel_alloc())) {
04981 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04982 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
04983 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04984 ast = ast_channel_unref(ast);
04985 } else {
04986 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04987 }
04988 } else {
04989 fprintf(p, "New %s long %s msg in box %s\n"
04990 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
04991 }
04992
04993 fclose(p);
04994 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04995 ast_safe_system(tmp2);
04996 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
04997 ast_free(str1);
04998 ast_free(str2);
04999 return 0;
05000 }
05001
05002
05003
05004
05005
05006
05007
05008
05009
05010
05011 static int get_date(char *s, int len)
05012 {
05013 struct ast_tm tm;
05014 struct timeval t = ast_tvnow();
05015
05016 ast_localtime(&t, &tm, "UTC");
05017
05018 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05019 }
05020
05021 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05022 {
05023 int res;
05024 char fn[PATH_MAX];
05025 char dest[PATH_MAX];
05026
05027 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05028
05029 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05030 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05031 return -1;
05032 }
05033
05034 RETRIEVE(fn, -1, ext, context);
05035 if (ast_fileexists(fn, NULL, NULL) > 0) {
05036 res = ast_stream_and_wait(chan, fn, ecodes);
05037 if (res) {
05038 DISPOSE(fn, -1);
05039 return res;
05040 }
05041 } else {
05042
05043 DISPOSE(fn, -1);
05044 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05045 if (res)
05046 return res;
05047 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05048 if (res)
05049 return res;
05050 }
05051 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05052 return res;
05053 }
05054
05055 static void free_zone(struct vm_zone *z)
05056 {
05057 ast_free(z);
05058 }
05059
05060 #ifdef ODBC_STORAGE
05061 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05062 {
05063 int x = -1;
05064 int res;
05065 SQLHSTMT stmt = NULL;
05066 char sql[PATH_MAX];
05067 char rowdata[20];
05068 char tmp[PATH_MAX] = "";
05069 struct odbc_obj *obj = NULL;
05070 char *context;
05071 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05072
05073 if (newmsgs)
05074 *newmsgs = 0;
05075 if (oldmsgs)
05076 *oldmsgs = 0;
05077 if (urgentmsgs)
05078 *urgentmsgs = 0;
05079
05080
05081 if (ast_strlen_zero(mailbox))
05082 return 0;
05083
05084 ast_copy_string(tmp, mailbox, sizeof(tmp));
05085
05086 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05087 int u, n, o;
05088 char *next, *remaining = tmp;
05089 while ((next = strsep(&remaining, " ,"))) {
05090 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05091 return -1;
05092 }
05093 if (urgentmsgs) {
05094 *urgentmsgs += u;
05095 }
05096 if (newmsgs) {
05097 *newmsgs += n;
05098 }
05099 if (oldmsgs) {
05100 *oldmsgs += o;
05101 }
05102 }
05103 return 0;
05104 }
05105
05106 context = strchr(tmp, '@');
05107 if (context) {
05108 *context = '\0';
05109 context++;
05110 } else
05111 context = "default";
05112
05113 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05114 do {
05115 if (newmsgs) {
05116 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05117 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05118 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05119 break;
05120 }
05121 res = SQLFetch(stmt);
05122 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05123 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05124 break;
05125 }
05126 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05127 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05128 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05129 break;
05130 }
05131 *newmsgs = atoi(rowdata);
05132 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05133 }
05134
05135 if (oldmsgs) {
05136 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05137 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05138 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05139 break;
05140 }
05141 res = SQLFetch(stmt);
05142 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05143 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05144 break;
05145 }
05146 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05147 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05148 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05149 break;
05150 }
05151 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05152 *oldmsgs = atoi(rowdata);
05153 }
05154
05155 if (urgentmsgs) {
05156 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05157 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05158 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05159 break;
05160 }
05161 res = SQLFetch(stmt);
05162 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05163 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05164 break;
05165 }
05166 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05167 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05168 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05169 break;
05170 }
05171 *urgentmsgs = atoi(rowdata);
05172 }
05173
05174 x = 0;
05175 } while (0);
05176 } else {
05177 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05178 }
05179
05180 if (stmt) {
05181 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05182 }
05183 if (obj) {
05184 ast_odbc_release_obj(obj);
05185 }
05186 return x;
05187 }
05188
05189
05190
05191
05192
05193
05194
05195
05196
05197
05198 static int messagecount(const char *context, const char *mailbox, const char *folder)
05199 {
05200 struct odbc_obj *obj = NULL;
05201 int nummsgs = 0;
05202 int res;
05203 SQLHSTMT stmt = NULL;
05204 char sql[PATH_MAX];
05205 char rowdata[20];
05206 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05207 if (!folder)
05208 folder = "INBOX";
05209
05210 if (ast_strlen_zero(mailbox))
05211 return 0;
05212
05213 obj = ast_odbc_request_obj(odbc_database, 0);
05214 if (obj) {
05215 if (!strcmp(folder, "INBOX")) {
05216 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);
05217 } else {
05218 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05219 }
05220 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05221 if (!stmt) {
05222 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05223 goto yuck;
05224 }
05225 res = SQLFetch(stmt);
05226 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05227 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05228 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05229 goto yuck;
05230 }
05231 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05232 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05233 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05234 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05235 goto yuck;
05236 }
05237 nummsgs = atoi(rowdata);
05238 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05239 } else
05240 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05241
05242 yuck:
05243 if (obj)
05244 ast_odbc_release_obj(obj);
05245 return nummsgs;
05246 }
05247
05248
05249
05250
05251
05252
05253
05254
05255
05256 static int has_voicemail(const char *mailbox, const char *folder)
05257 {
05258 char tmp[256], *tmp2 = tmp, *box, *context;
05259 ast_copy_string(tmp, mailbox, sizeof(tmp));
05260 while ((context = box = strsep(&tmp2, ",&"))) {
05261 strsep(&context, "@");
05262 if (ast_strlen_zero(context))
05263 context = "default";
05264 if (messagecount(context, box, folder))
05265 return 1;
05266 }
05267 return 0;
05268 }
05269 #endif
05270 #ifndef IMAP_STORAGE
05271
05272
05273
05274
05275
05276
05277
05278
05279
05280
05281
05282
05283
05284
05285
05286
05287 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)
05288 {
05289 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05290 const char *frombox = mbox(vmu, imbox);
05291 const char *userfolder;
05292 int recipmsgnum;
05293 int res = 0;
05294
05295 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05296
05297 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05298 userfolder = "Urgent";
05299 } else {
05300 userfolder = "INBOX";
05301 }
05302
05303 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05304
05305 if (!dir)
05306 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05307 else
05308 ast_copy_string(fromdir, dir, sizeof(fromdir));
05309
05310 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05311 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05312
05313 if (vm_lock_path(todir))
05314 return ERROR_LOCK_PATH;
05315
05316 recipmsgnum = last_message_index(recip, todir) + 1;
05317 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05318 make_file(topath, sizeof(topath), todir, recipmsgnum);
05319 #ifndef ODBC_STORAGE
05320 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05321 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05322 } else {
05323 #endif
05324
05325
05326
05327 copy_plain_file(frompath, topath);
05328 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05329 vm_delete(topath);
05330 #ifndef ODBC_STORAGE
05331 }
05332 #endif
05333 } else {
05334 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05335 res = -1;
05336 }
05337 ast_unlock_path(todir);
05338 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05339 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05340 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05341 flag);
05342
05343 return res;
05344 }
05345 #endif
05346 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05347
05348 static int messagecount(const char *context, const char *mailbox, const char *folder)
05349 {
05350 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05351 }
05352
05353 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05354 {
05355 DIR *dir;
05356 struct dirent *de;
05357 char fn[256];
05358 int ret = 0;
05359
05360
05361 if (ast_strlen_zero(mailbox))
05362 return 0;
05363
05364 if (ast_strlen_zero(folder))
05365 folder = "INBOX";
05366 if (ast_strlen_zero(context))
05367 context = "default";
05368
05369 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05370
05371 if (!(dir = opendir(fn)))
05372 return 0;
05373
05374 while ((de = readdir(dir))) {
05375 if (!strncasecmp(de->d_name, "msg", 3)) {
05376 if (shortcircuit) {
05377 ret = 1;
05378 break;
05379 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05380 ret++;
05381 }
05382 }
05383 }
05384
05385 closedir(dir);
05386
05387 return ret;
05388 }
05389
05390
05391
05392
05393
05394
05395
05396
05397
05398
05399 static int has_voicemail(const char *mailbox, const char *folder)
05400 {
05401 char tmp[256], *tmp2 = tmp, *box, *context;
05402 ast_copy_string(tmp, mailbox, sizeof(tmp));
05403 if (ast_strlen_zero(folder)) {
05404 folder = "INBOX";
05405 }
05406 while ((box = strsep(&tmp2, ",&"))) {
05407 if ((context = strchr(box, '@')))
05408 *context++ = '\0';
05409 else
05410 context = "default";
05411 if (__has_voicemail(context, box, folder, 1))
05412 return 1;
05413
05414 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05415 return 1;
05416 }
05417 }
05418 return 0;
05419 }
05420
05421
05422 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05423 {
05424 char tmp[256];
05425 char *context;
05426
05427
05428 if (ast_strlen_zero(mailbox))
05429 return 0;
05430
05431 if (newmsgs)
05432 *newmsgs = 0;
05433 if (oldmsgs)
05434 *oldmsgs = 0;
05435 if (urgentmsgs)
05436 *urgentmsgs = 0;
05437
05438 if (strchr(mailbox, ',')) {
05439 int tmpnew, tmpold, tmpurgent;
05440 char *mb, *cur;
05441
05442 ast_copy_string(tmp, mailbox, sizeof(tmp));
05443 mb = tmp;
05444 while ((cur = strsep(&mb, ", "))) {
05445 if (!ast_strlen_zero(cur)) {
05446 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05447 return -1;
05448 else {
05449 if (newmsgs)
05450 *newmsgs += tmpnew;
05451 if (oldmsgs)
05452 *oldmsgs += tmpold;
05453 if (urgentmsgs)
05454 *urgentmsgs += tmpurgent;
05455 }
05456 }
05457 }
05458 return 0;
05459 }
05460
05461 ast_copy_string(tmp, mailbox, sizeof(tmp));
05462
05463 if ((context = strchr(tmp, '@')))
05464 *context++ = '\0';
05465 else
05466 context = "default";
05467
05468 if (newmsgs)
05469 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05470 if (oldmsgs)
05471 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05472 if (urgentmsgs)
05473 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05474
05475 return 0;
05476 }
05477
05478 #endif
05479
05480
05481 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05482 {
05483 int urgentmsgs = 0;
05484 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05485 if (newmsgs) {
05486 *newmsgs += urgentmsgs;
05487 }
05488 return res;
05489 }
05490
05491 static void run_externnotify(char *context, char *extension, const char *flag)
05492 {
05493 char arguments[255];
05494 char ext_context[256] = "";
05495 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05496 struct ast_smdi_mwi_message *mwi_msg;
05497
05498 if (!ast_strlen_zero(context))
05499 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05500 else
05501 ast_copy_string(ext_context, extension, sizeof(ext_context));
05502
05503 if (smdi_iface) {
05504 if (ast_app_has_voicemail(ext_context, NULL))
05505 ast_smdi_mwi_set(smdi_iface, extension);
05506 else
05507 ast_smdi_mwi_unset(smdi_iface, extension);
05508
05509 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05510 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05511 if (!strncmp(mwi_msg->cause, "INV", 3))
05512 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05513 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05514 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05515 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05516 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05517 } else {
05518 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05519 }
05520 }
05521
05522 if (!ast_strlen_zero(externnotify)) {
05523 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05524 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05525 } else {
05526 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05527 ast_debug(1, "Executing %s\n", arguments);
05528 ast_safe_system(arguments);
05529 }
05530 }
05531 }
05532
05533
05534
05535
05536
05537
05538 struct leave_vm_options {
05539 unsigned int flags;
05540 signed char record_gain;
05541 char *exitcontext;
05542 };
05543
05544
05545
05546
05547
05548
05549
05550
05551
05552
05553
05554 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05555 {
05556 #ifdef IMAP_STORAGE
05557 int newmsgs, oldmsgs;
05558 #else
05559 char urgdir[PATH_MAX];
05560 #endif
05561 char txtfile[PATH_MAX];
05562 char tmptxtfile[PATH_MAX];
05563 struct vm_state *vms = NULL;
05564 char callerid[256];
05565 FILE *txt;
05566 char date[256];
05567 int txtdes;
05568 int res = 0;
05569 int msgnum;
05570 int duration = 0;
05571 int sound_duration = 0;
05572 int ausemacro = 0;
05573 int ousemacro = 0;
05574 int ouseexten = 0;
05575 char tmpdur[16];
05576 char priority[16];
05577 char origtime[16];
05578 char dir[PATH_MAX];
05579 char tmpdir[PATH_MAX];
05580 char fn[PATH_MAX];
05581 char prefile[PATH_MAX] = "";
05582 char tempfile[PATH_MAX] = "";
05583 char ext_context[256] = "";
05584 char fmt[80];
05585 char *context;
05586 char ecodes[17] = "#";
05587 struct ast_str *tmp = ast_str_create(16);
05588 char *tmpptr;
05589 struct ast_vm_user *vmu;
05590 struct ast_vm_user svm;
05591 const char *category = NULL;
05592 const char *code;
05593 const char *alldtmf = "0123456789ABCD*#";
05594 char flag[80];
05595
05596 if (!tmp) {
05597 return -1;
05598 }
05599
05600 ast_str_set(&tmp, 0, "%s", ext);
05601 ext = ast_str_buffer(tmp);
05602 if ((context = strchr(ext, '@'))) {
05603 *context++ = '\0';
05604 tmpptr = strchr(context, '&');
05605 } else {
05606 tmpptr = strchr(ext, '&');
05607 }
05608
05609 if (tmpptr)
05610 *tmpptr++ = '\0';
05611
05612 ast_channel_lock(chan);
05613 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05614 category = ast_strdupa(category);
05615 }
05616 ast_channel_unlock(chan);
05617
05618 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05619 ast_copy_string(flag, "Urgent", sizeof(flag));
05620 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05621 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05622 } else {
05623 flag[0] = '\0';
05624 }
05625
05626 ast_debug(3, "Before find_user\n");
05627 if (!(vmu = find_user(&svm, context, ext))) {
05628 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05629 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05630 ast_free(tmp);
05631 return res;
05632 }
05633
05634 if (strcmp(vmu->context, "default"))
05635 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05636 else
05637 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05638
05639
05640
05641
05642
05643
05644 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05645 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05646 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05647 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05648 }
05649
05650
05651
05652
05653 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05654 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05655 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05656 ast_free(tmp);
05657 return -1;
05658 }
05659 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05660 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05661 ast_copy_string(prefile, tempfile, sizeof(prefile));
05662
05663 DISPOSE(tempfile, -1);
05664
05665 #ifndef IMAP_STORAGE
05666 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05667 #else
05668 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05669 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05670 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05671 }
05672 #endif
05673
05674
05675 if (ast_test_flag(vmu, VM_OPERATOR)) {
05676 if (!ast_strlen_zero(vmu->exit)) {
05677 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05678 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05679 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05680 ouseexten = 1;
05681 }
05682 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05683 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05684 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05685 ouseexten = 1;
05686 } else if (!ast_strlen_zero(chan->macrocontext)
05687 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05688 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05689 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05690 ousemacro = 1;
05691 }
05692 }
05693
05694 if (!ast_strlen_zero(vmu->exit)) {
05695 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05696 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05697 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05698 }
05699 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05700 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05701 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05702 } else if (!ast_strlen_zero(chan->macrocontext)
05703 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05704 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05705 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05706 ausemacro = 1;
05707 }
05708
05709 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05710 for (code = alldtmf; *code; code++) {
05711 char e[2] = "";
05712 e[0] = *code;
05713 if (strchr(ecodes, e[0]) == NULL
05714 && ast_canmatch_extension(chan, chan->context, e, 1,
05715 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05716 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05717 }
05718 }
05719 }
05720
05721
05722 if (!ast_strlen_zero(prefile)) {
05723 #ifdef ODBC_STORAGE
05724 int success =
05725 #endif
05726 RETRIEVE(prefile, -1, ext, context);
05727 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05728 if (ast_streamfile(chan, prefile, chan->language) > -1)
05729 res = ast_waitstream(chan, ecodes);
05730 #ifdef ODBC_STORAGE
05731 if (success == -1) {
05732
05733 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05734 store_file(prefile, vmu->mailbox, vmu->context, -1);
05735 }
05736 #endif
05737 } else {
05738 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05739 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05740 }
05741 DISPOSE(prefile, -1);
05742 if (res < 0) {
05743 ast_debug(1, "Hang up during prefile playback\n");
05744 free_user(vmu);
05745 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05746 ast_free(tmp);
05747 return -1;
05748 }
05749 }
05750 if (res == '#') {
05751
05752 ast_set_flag(options, OPT_SILENT);
05753 res = 0;
05754 }
05755
05756 if (vmu->maxmsg == 0) {
05757 if (option_debug > 2)
05758 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05759 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05760 goto leave_vm_out;
05761 }
05762 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05763 res = ast_stream_and_wait(chan, INTRO, ecodes);
05764 if (res == '#') {
05765 ast_set_flag(options, OPT_SILENT);
05766 res = 0;
05767 }
05768 }
05769 if (res > 0)
05770 ast_stopstream(chan);
05771
05772
05773 if (res == '*') {
05774 chan->exten[0] = 'a';
05775 chan->exten[1] = '\0';
05776 if (!ast_strlen_zero(vmu->exit)) {
05777 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05778 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05779 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05780 }
05781 chan->priority = 0;
05782 free_user(vmu);
05783 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05784 ast_free(tmp);
05785 return 0;
05786 }
05787
05788
05789 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05790 transfer:
05791 if (ouseexten || ousemacro) {
05792 chan->exten[0] = 'o';
05793 chan->exten[1] = '\0';
05794 if (!ast_strlen_zero(vmu->exit)) {
05795 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05796 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05797 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05798 }
05799 ast_play_and_wait(chan, "transfer");
05800 chan->priority = 0;
05801 free_user(vmu);
05802 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05803 }
05804 ast_free(tmp);
05805 return OPERATOR_EXIT;
05806 }
05807
05808
05809 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05810 if (!ast_strlen_zero(options->exitcontext))
05811 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05812 free_user(vmu);
05813 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05814 ast_free(tmp);
05815 return res;
05816 }
05817
05818 if (res < 0) {
05819 free_user(vmu);
05820 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05821 ast_free(tmp);
05822 return -1;
05823 }
05824
05825 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05826 if (!ast_strlen_zero(fmt)) {
05827 msgnum = 0;
05828
05829 #ifdef IMAP_STORAGE
05830
05831
05832 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05833 if (res < 0) {
05834 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05835 ast_free(tmp);
05836 return -1;
05837 }
05838 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05839
05840
05841
05842
05843 if (!(vms = create_vm_state_from_user(vmu))) {
05844 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05845 ast_free(tmp);
05846 return -1;
05847 }
05848 }
05849 vms->newmessages++;
05850
05851
05852 msgnum = newmsgs + oldmsgs;
05853 ast_debug(3, "Messagecount set to %d\n", msgnum);
05854 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05855
05856 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05857
05858 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05859 goto leave_vm_out;
05860 }
05861 #else
05862 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05863 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05864 if (!res)
05865 res = ast_waitstream(chan, "");
05866 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05867 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05868 inprocess_count(vmu->mailbox, vmu->context, -1);
05869 goto leave_vm_out;
05870 }
05871
05872 #endif
05873 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05874 txtdes = mkstemp(tmptxtfile);
05875 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05876 if (txtdes < 0) {
05877 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05878 if (!res)
05879 res = ast_waitstream(chan, "");
05880 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05881 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05882 inprocess_count(vmu->mailbox, vmu->context, -1);
05883 goto leave_vm_out;
05884 }
05885
05886
05887 if (res >= 0) {
05888
05889 res = ast_stream_and_wait(chan, "beep", "");
05890 }
05891
05892
05893 if (ast_check_realtime("voicemail_data")) {
05894 snprintf(priority, sizeof(priority), "%d", chan->priority);
05895 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05896 get_date(date, sizeof(date));
05897 ast_callerid_merge(callerid, sizeof(callerid),
05898 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05899 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05900 "Unknown");
05901 ast_store_realtime("voicemail_data",
05902 "origmailbox", ext,
05903 "context", chan->context,
05904 "macrocontext", chan->macrocontext,
05905 "exten", chan->exten,
05906 "priority", priority,
05907 "callerchan", chan->name,
05908 "callerid", callerid,
05909 "origdate", date,
05910 "origtime", origtime,
05911 "category", S_OR(category, ""),
05912 "filename", tmptxtfile,
05913 SENTINEL);
05914 }
05915
05916
05917 txt = fdopen(txtdes, "w+");
05918 if (txt) {
05919 get_date(date, sizeof(date));
05920 ast_callerid_merge(callerid, sizeof(callerid),
05921 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05922 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05923 "Unknown");
05924 fprintf(txt,
05925 ";\n"
05926 "; Message Information file\n"
05927 ";\n"
05928 "[message]\n"
05929 "origmailbox=%s\n"
05930 "context=%s\n"
05931 "macrocontext=%s\n"
05932 "exten=%s\n"
05933 "rdnis=%s\n"
05934 "priority=%d\n"
05935 "callerchan=%s\n"
05936 "callerid=%s\n"
05937 "origdate=%s\n"
05938 "origtime=%ld\n"
05939 "category=%s\n",
05940 ext,
05941 chan->context,
05942 chan->macrocontext,
05943 chan->exten,
05944 S_COR(chan->redirecting.from.number.valid,
05945 chan->redirecting.from.number.str, "unknown"),
05946 chan->priority,
05947 chan->name,
05948 callerid,
05949 date, (long) time(NULL),
05950 category ? category : "");
05951 } else {
05952 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05953 inprocess_count(vmu->mailbox, vmu->context, -1);
05954 if (ast_check_realtime("voicemail_data")) {
05955 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05956 }
05957 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05958 goto leave_vm_out;
05959 }
05960 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
05961
05962 if (txt) {
05963 fprintf(txt, "flag=%s\n", flag);
05964 if (sound_duration < vmu->minsecs) {
05965 fclose(txt);
05966 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
05967 ast_filedelete(tmptxtfile, NULL);
05968 unlink(tmptxtfile);
05969 if (ast_check_realtime("voicemail_data")) {
05970 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05971 }
05972 inprocess_count(vmu->mailbox, vmu->context, -1);
05973 } else {
05974 fprintf(txt, "duration=%d\n", duration);
05975 fclose(txt);
05976 if (vm_lock_path(dir)) {
05977 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05978
05979 ast_filedelete(tmptxtfile, NULL);
05980 unlink(tmptxtfile);
05981 inprocess_count(vmu->mailbox, vmu->context, -1);
05982 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
05983 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
05984 unlink(tmptxtfile);
05985 ast_unlock_path(dir);
05986 inprocess_count(vmu->mailbox, vmu->context, -1);
05987 if (ast_check_realtime("voicemail_data")) {
05988 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05989 }
05990 } else {
05991 #ifndef IMAP_STORAGE
05992 msgnum = last_message_index(vmu, dir) + 1;
05993 #endif
05994 make_file(fn, sizeof(fn), dir, msgnum);
05995
05996
05997 #ifndef IMAP_STORAGE
05998 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
05999 #else
06000 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06001 #endif
06002
06003 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06004 ast_filerename(tmptxtfile, fn, NULL);
06005 rename(tmptxtfile, txtfile);
06006 inprocess_count(vmu->mailbox, vmu->context, -1);
06007
06008
06009
06010 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06011 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06012
06013 ast_unlock_path(dir);
06014 if (ast_check_realtime("voicemail_data")) {
06015 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06016 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06017 }
06018
06019
06020
06021 if (ast_fileexists(fn, NULL, NULL) > 0) {
06022 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06023 }
06024
06025
06026 while (tmpptr) {
06027 struct ast_vm_user recipu, *recip;
06028 char *exten, *cntx;
06029
06030 exten = strsep(&tmpptr, "&");
06031 cntx = strchr(exten, '@');
06032 if (cntx) {
06033 *cntx = '\0';
06034 cntx++;
06035 }
06036 if ((recip = find_user(&recipu, cntx, exten))) {
06037 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06038 free_user(recip);
06039 }
06040 }
06041 #ifndef IMAP_STORAGE
06042 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06043
06044 char sfn[PATH_MAX];
06045 char dfn[PATH_MAX];
06046 int x;
06047
06048 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06049 x = last_message_index(vmu, urgdir) + 1;
06050 make_file(sfn, sizeof(sfn), dir, msgnum);
06051 make_file(dfn, sizeof(dfn), urgdir, x);
06052 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06053 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06054
06055 ast_copy_string(fn, dfn, sizeof(fn));
06056 msgnum = x;
06057 }
06058 #endif
06059
06060 if (ast_fileexists(fn, NULL, NULL)) {
06061 #ifdef IMAP_STORAGE
06062 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06063 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06064 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06065 flag);
06066 #else
06067 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06068 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06069 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06070 flag);
06071 #endif
06072 }
06073
06074
06075 if (ast_fileexists(fn, NULL, NULL)) {
06076 DISPOSE(dir, msgnum);
06077 }
06078 }
06079 }
06080 } else {
06081 inprocess_count(vmu->mailbox, vmu->context, -1);
06082 }
06083 if (res == '0') {
06084 goto transfer;
06085 } else if (res > 0 && res != 't')
06086 res = 0;
06087
06088 if (sound_duration < vmu->minsecs)
06089
06090 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06091 else
06092 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06093 } else
06094 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06095 leave_vm_out:
06096 free_user(vmu);
06097
06098 #ifdef IMAP_STORAGE
06099
06100 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06101 if (expungeonhangup == 1) {
06102 ast_mutex_lock(&vms->lock);
06103 #ifdef HAVE_IMAP_TK2006
06104 if (LEVELUIDPLUS (vms->mailstream)) {
06105 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06106 } else
06107 #endif
06108 mail_expunge(vms->mailstream);
06109 ast_mutex_unlock(&vms->lock);
06110 }
06111 #endif
06112
06113 ast_free(tmp);
06114 return res;
06115 }
06116
06117 #if !defined(IMAP_STORAGE)
06118 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06119 {
06120
06121
06122 int x, dest;
06123 char sfn[PATH_MAX];
06124 char dfn[PATH_MAX];
06125
06126 if (vm_lock_path(dir)) {
06127 return ERROR_LOCK_PATH;
06128 }
06129
06130 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06131 make_file(sfn, sizeof(sfn), dir, x);
06132 if (EXISTS(dir, x, sfn, NULL)) {
06133
06134 if (x != dest) {
06135 make_file(dfn, sizeof(dfn), dir, dest);
06136 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06137 }
06138
06139 dest++;
06140 }
06141 }
06142 ast_unlock_path(dir);
06143
06144 return dest;
06145 }
06146 #endif
06147
06148 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06149 {
06150 int d;
06151 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06152 return d;
06153 }
06154
06155 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06156 {
06157 #ifdef IMAP_STORAGE
06158
06159
06160 char sequence[10];
06161 char mailbox[256];
06162 int res;
06163
06164
06165 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06166
06167 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06168 ast_mutex_lock(&vms->lock);
06169
06170 if (box == OLD_FOLDER) {
06171 mail_setflag(vms->mailstream, sequence, "\\Seen");
06172 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06173 } else if (box == NEW_FOLDER) {
06174 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06175 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06176 }
06177 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06178 ast_mutex_unlock(&vms->lock);
06179 return 0;
06180 }
06181
06182 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06183 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06184 if (mail_create(vms->mailstream, mailbox) == NIL)
06185 ast_debug(5, "Folder exists.\n");
06186 else
06187 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06188 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06189 ast_mutex_unlock(&vms->lock);
06190 return res;
06191 #else
06192 char *dir = vms->curdir;
06193 char *username = vms->username;
06194 char *context = vmu->context;
06195 char sfn[PATH_MAX];
06196 char dfn[PATH_MAX];
06197 char ddir[PATH_MAX];
06198 const char *dbox = mbox(vmu, box);
06199 int x, i;
06200 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06201
06202 if (vm_lock_path(ddir))
06203 return ERROR_LOCK_PATH;
06204
06205 x = last_message_index(vmu, ddir) + 1;
06206
06207 if (box == 10 && x >= vmu->maxdeletedmsg) {
06208 x--;
06209 for (i = 1; i <= x; i++) {
06210
06211 make_file(sfn, sizeof(sfn), ddir, i);
06212 make_file(dfn, sizeof(dfn), ddir, i - 1);
06213 if (EXISTS(ddir, i, sfn, NULL)) {
06214 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06215 } else
06216 break;
06217 }
06218 } else {
06219 if (x >= vmu->maxmsg) {
06220 ast_unlock_path(ddir);
06221 return -1;
06222 }
06223 }
06224 make_file(sfn, sizeof(sfn), dir, msg);
06225 make_file(dfn, sizeof(dfn), ddir, x);
06226 if (strcmp(sfn, dfn)) {
06227 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06228 }
06229 ast_unlock_path(ddir);
06230 #endif
06231 return 0;
06232 }
06233
06234 static int adsi_logo(unsigned char *buf)
06235 {
06236 int bytes = 0;
06237 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06238 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06239 return bytes;
06240 }
06241
06242 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06243 {
06244 unsigned char buf[256];
06245 int bytes = 0;
06246 int x;
06247 char num[5];
06248
06249 *useadsi = 0;
06250 bytes += ast_adsi_data_mode(buf + bytes);
06251 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06252
06253 bytes = 0;
06254 bytes += adsi_logo(buf);
06255 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06256 #ifdef DISPLAY
06257 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06258 #endif
06259 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06260 bytes += ast_adsi_data_mode(buf + bytes);
06261 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06262
06263 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06264 bytes = 0;
06265 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06266 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06267 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06268 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06269 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06270 return 0;
06271 }
06272
06273 #ifdef DISPLAY
06274
06275 bytes = 0;
06276 bytes += ast_adsi_logo(buf);
06277 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06278 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06279 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06280 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06281 #endif
06282 bytes = 0;
06283 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06284 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06285 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06286 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06287 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06288 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06289 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06290
06291 #ifdef DISPLAY
06292
06293 bytes = 0;
06294 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06295 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06296
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
06301 bytes = 0;
06302
06303 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06304 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06305 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06306 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06307 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06308 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06309 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06310
06311 #ifdef DISPLAY
06312
06313 bytes = 0;
06314 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
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 for (x = 0; x < 5; x++) {
06321 snprintf(num, sizeof(num), "%d", x);
06322 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06323 }
06324 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06325 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06326
06327 #ifdef DISPLAY
06328
06329 bytes = 0;
06330 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06331 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06332 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06333 #endif
06334
06335 if (ast_adsi_end_download(chan)) {
06336 bytes = 0;
06337 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06338 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06339 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06340 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06341 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06342 return 0;
06343 }
06344 bytes = 0;
06345 bytes += ast_adsi_download_disconnect(buf + bytes);
06346 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06347 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06348
06349 ast_debug(1, "Done downloading scripts...\n");
06350
06351 #ifdef DISPLAY
06352
06353 bytes = 0;
06354 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06355 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06356 #endif
06357 ast_debug(1, "Restarting session...\n");
06358
06359 bytes = 0;
06360
06361 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06362 *useadsi = 1;
06363 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06364 } else
06365 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06366
06367 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06368 return 0;
06369 }
06370
06371 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06372 {
06373 int x;
06374 if (!ast_adsi_available(chan))
06375 return;
06376 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06377 if (x < 0)
06378 return;
06379 if (!x) {
06380 if (adsi_load_vmail(chan, useadsi)) {
06381 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06382 return;
06383 }
06384 } else
06385 *useadsi = 1;
06386 }
06387
06388 static void adsi_login(struct ast_channel *chan)
06389 {
06390 unsigned char buf[256];
06391 int bytes = 0;
06392 unsigned char keys[8];
06393 int x;
06394 if (!ast_adsi_available(chan))
06395 return;
06396
06397 for (x = 0; x < 8; x++)
06398 keys[x] = 0;
06399
06400 keys[3] = ADSI_KEY_APPS + 3;
06401
06402 bytes += adsi_logo(buf + bytes);
06403 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06404 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06405 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06406 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06407 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06408 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06409 bytes += ast_adsi_set_keys(buf + bytes, keys);
06410 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06411 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06412 }
06413
06414 static void adsi_password(struct ast_channel *chan)
06415 {
06416 unsigned char buf[256];
06417 int bytes = 0;
06418 unsigned char keys[8];
06419 int x;
06420 if (!ast_adsi_available(chan))
06421 return;
06422
06423 for (x = 0; x < 8; x++)
06424 keys[x] = 0;
06425
06426 keys[3] = ADSI_KEY_APPS + 3;
06427
06428 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06429 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06430 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06431 bytes += ast_adsi_set_keys(buf + bytes, keys);
06432 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06433 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06434 }
06435
06436 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06437 {
06438 unsigned char buf[256];
06439 int bytes = 0;
06440 unsigned char keys[8];
06441 int x, y;
06442
06443 if (!ast_adsi_available(chan))
06444 return;
06445
06446 for (x = 0; x < 5; x++) {
06447 y = ADSI_KEY_APPS + 12 + start + x;
06448 if (y > ADSI_KEY_APPS + 12 + 4)
06449 y = 0;
06450 keys[x] = ADSI_KEY_SKT | y;
06451 }
06452 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06453 keys[6] = 0;
06454 keys[7] = 0;
06455
06456 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06457 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06458 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06459 bytes += ast_adsi_set_keys(buf + bytes, keys);
06460 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06461
06462 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06463 }
06464
06465 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06466 {
06467 int bytes = 0;
06468 unsigned char buf[256];
06469 char buf1[256], buf2[256];
06470 char fn2[PATH_MAX];
06471
06472 char cid[256] = "";
06473 char *val;
06474 char *name, *num;
06475 char datetime[21] = "";
06476 FILE *f;
06477
06478 unsigned char keys[8];
06479
06480 int x;
06481
06482 if (!ast_adsi_available(chan))
06483 return;
06484
06485
06486 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06487 f = fopen(fn2, "r");
06488 if (f) {
06489 while (!feof(f)) {
06490 if (!fgets((char *) buf, sizeof(buf), f)) {
06491 continue;
06492 }
06493 if (!feof(f)) {
06494 char *stringp = NULL;
06495 stringp = (char *) buf;
06496 strsep(&stringp, "=");
06497 val = strsep(&stringp, "=");
06498 if (!ast_strlen_zero(val)) {
06499 if (!strcmp((char *) buf, "callerid"))
06500 ast_copy_string(cid, val, sizeof(cid));
06501 if (!strcmp((char *) buf, "origdate"))
06502 ast_copy_string(datetime, val, sizeof(datetime));
06503 }
06504 }
06505 }
06506 fclose(f);
06507 }
06508
06509 for (x = 0; x < 5; x++)
06510 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06511 keys[6] = 0x0;
06512 keys[7] = 0x0;
06513
06514 if (!vms->curmsg) {
06515
06516 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06517 }
06518 if (vms->curmsg >= vms->lastmsg) {
06519
06520 if (vms->curmsg) {
06521
06522 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06523 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06524
06525 } else {
06526
06527 keys[3] = 1;
06528 }
06529 }
06530
06531 if (!ast_strlen_zero(cid)) {
06532 ast_callerid_parse(cid, &name, &num);
06533 if (!name)
06534 name = num;
06535 } else
06536 name = "Unknown Caller";
06537
06538
06539
06540 if (vms->deleted[vms->curmsg])
06541 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06542
06543
06544 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06545 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06546 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06547 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06548
06549 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06550 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06551 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06552 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06553 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06554 bytes += ast_adsi_set_keys(buf + bytes, keys);
06555 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06556
06557 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06558 }
06559
06560 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06561 {
06562 int bytes = 0;
06563 unsigned char buf[256];
06564 unsigned char keys[8];
06565
06566 int x;
06567
06568 if (!ast_adsi_available(chan))
06569 return;
06570
06571
06572 for (x = 0; x < 5; x++)
06573 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06574
06575 keys[6] = 0x0;
06576 keys[7] = 0x0;
06577
06578 if (!vms->curmsg) {
06579
06580 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06581 }
06582 if (vms->curmsg >= vms->lastmsg) {
06583
06584 if (vms->curmsg) {
06585
06586 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06587 } else {
06588
06589 keys[3] = 1;
06590 }
06591 }
06592
06593
06594 if (vms->deleted[vms->curmsg])
06595 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06596
06597
06598 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06599 bytes += ast_adsi_set_keys(buf + bytes, keys);
06600 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06601
06602 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06603 }
06604
06605 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06606 {
06607 unsigned char buf[256] = "";
06608 char buf1[256] = "", buf2[256] = "";
06609 int bytes = 0;
06610 unsigned char keys[8];
06611 int x;
06612
06613 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06614 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06615 if (!ast_adsi_available(chan))
06616 return;
06617 if (vms->newmessages) {
06618 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06619 if (vms->oldmessages) {
06620 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06621 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06622 } else {
06623 snprintf(buf2, sizeof(buf2), "%s.", newm);
06624 }
06625 } else if (vms->oldmessages) {
06626 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06627 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06628 } else {
06629 strcpy(buf1, "You have no messages.");
06630 buf2[0] = ' ';
06631 buf2[1] = '\0';
06632 }
06633 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06634 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06635 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06636
06637 for (x = 0; x < 6; x++)
06638 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06639 keys[6] = 0;
06640 keys[7] = 0;
06641
06642
06643 if (vms->lastmsg < 0)
06644 keys[0] = 1;
06645 bytes += ast_adsi_set_keys(buf + bytes, keys);
06646
06647 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06648
06649 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06650 }
06651
06652 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06653 {
06654 unsigned char buf[256] = "";
06655 char buf1[256] = "", buf2[256] = "";
06656 int bytes = 0;
06657 unsigned char keys[8];
06658 int x;
06659
06660 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06661
06662 if (!ast_adsi_available(chan))
06663 return;
06664
06665
06666 for (x = 0; x < 6; x++)
06667 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06668
06669 keys[6] = 0;
06670 keys[7] = 0;
06671
06672 if ((vms->lastmsg + 1) < 1)
06673 keys[0] = 0;
06674
06675 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06676 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06677
06678 if (vms->lastmsg + 1)
06679 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06680 else
06681 strcpy(buf2, "no messages.");
06682 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06683 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06684 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06685 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06686 bytes += ast_adsi_set_keys(buf + bytes, keys);
06687
06688 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06689
06690 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06691
06692 }
06693
06694
06695
06696
06697
06698
06699
06700
06701
06702
06703
06704
06705
06706
06707
06708 static void adsi_goodbye(struct ast_channel *chan)
06709 {
06710 unsigned char buf[256];
06711 int bytes = 0;
06712
06713 if (!ast_adsi_available(chan))
06714 return;
06715 bytes += adsi_logo(buf + bytes);
06716 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06717 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06718 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
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 static int get_folder(struct ast_channel *chan, int start)
06729 {
06730 int x;
06731 int d;
06732 char fn[PATH_MAX];
06733 d = ast_play_and_wait(chan, "vm-press");
06734 if (d)
06735 return d;
06736 for (x = start; x < 5; x++) {
06737 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06738 return d;
06739 d = ast_play_and_wait(chan, "vm-for");
06740 if (d)
06741 return d;
06742 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06743
06744
06745
06746
06747 if (x == 0) {
06748 if (ast_fileexists(fn, NULL, NULL)) {
06749 d = vm_play_folder_name(chan, fn);
06750 } else {
06751 ast_verb(1, "failed to find %s\n", fn);
06752 d = vm_play_folder_name(chan, "vm-INBOX");
06753 }
06754 } else {
06755 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06756 d = vm_play_folder_name(chan, fn);
06757 }
06758
06759 if (d)
06760 return d;
06761 d = ast_waitfordigit(chan, 500);
06762 if (d)
06763 return d;
06764 }
06765
06766 d = ast_play_and_wait(chan, "vm-tocancel");
06767 if (d)
06768 return d;
06769 d = ast_waitfordigit(chan, 4000);
06770 return d;
06771 }
06772
06773
06774
06775
06776
06777
06778
06779
06780
06781
06782
06783
06784
06785 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06786 {
06787 int res = 0;
06788 int loops = 0;
06789
06790 res = ast_play_and_wait(chan, fn);
06791 while (((res < '0') || (res > '9')) &&
06792 (res != '#') && (res >= 0) &&
06793 loops < 4) {
06794 res = get_folder(chan, 0);
06795 loops++;
06796 }
06797 if (loops == 4) {
06798 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06799 return '#';
06800 }
06801 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06802 return res;
06803 }
06804
06805
06806
06807
06808
06809
06810
06811
06812
06813
06814
06815
06816
06817
06818
06819
06820
06821
06822
06823 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06824 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06825 {
06826 int cmd = 0;
06827 int retries = 0, prepend_duration = 0, already_recorded = 0;
06828 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06829 char textfile[PATH_MAX];
06830 struct ast_config *msg_cfg;
06831 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06832 #ifndef IMAP_STORAGE
06833 signed char zero_gain = 0;
06834 #endif
06835 const char *duration_str;
06836
06837
06838 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06839 strcpy(textfile, msgfile);
06840 strcpy(backup, msgfile);
06841 strcpy(backup_textfile, msgfile);
06842 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06843 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06844 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06845
06846 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06847 *duration = atoi(duration_str);
06848 } else {
06849 *duration = 0;
06850 }
06851
06852 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06853 if (cmd)
06854 retries = 0;
06855 switch (cmd) {
06856 case '1':
06857
06858 #ifdef IMAP_STORAGE
06859
06860 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06861 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06862 ast_play_and_wait(chan, INTRO);
06863 ast_play_and_wait(chan, "beep");
06864 play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06865 cmd = 't';
06866 #else
06867
06868
06869
06870 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06871 strcpy(textfile, msgfile);
06872 strncat(textfile, ".txt", sizeof(textfile) - 1);
06873 *duration = 0;
06874
06875
06876 if (!msg_cfg) {
06877 cmd = 0;
06878 break;
06879 }
06880
06881
06882 #ifndef IMAP_STORAGE
06883 if (already_recorded) {
06884 ast_filecopy(backup, msgfile, NULL);
06885 copy(backup_textfile, textfile);
06886 }
06887 else {
06888 ast_filecopy(msgfile, backup, NULL);
06889 copy(textfile, backup_textfile);
06890 }
06891 #endif
06892 already_recorded = 1;
06893
06894 if (record_gain)
06895 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06896
06897 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06898
06899 if (cmd == 'S') {
06900 ast_stream_and_wait(chan, vm_pls_try_again, "");
06901 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06902 ast_filerename(backup, msgfile, NULL);
06903 }
06904
06905 if (record_gain)
06906 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06907
06908
06909 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06910 *duration = atoi(duration_str);
06911
06912 if (prepend_duration) {
06913 struct ast_category *msg_cat;
06914
06915 char duration_buf[12];
06916
06917 *duration += prepend_duration;
06918 msg_cat = ast_category_get(msg_cfg, "message");
06919 snprintf(duration_buf, 11, "%ld", *duration);
06920 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06921 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06922 }
06923 }
06924
06925 #endif
06926 break;
06927 case '2':
06928
06929 #ifdef IMAP_STORAGE
06930 *vms->introfn = '\0';
06931 #endif
06932 cmd = 't';
06933 break;
06934 case '*':
06935 cmd = '*';
06936 break;
06937 default:
06938
06939 already_recorded = 0;
06940
06941 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06942
06943 if (!cmd) {
06944 cmd = ast_play_and_wait(chan, "vm-starmain");
06945
06946 }
06947 if (!cmd) {
06948 cmd = ast_waitfordigit(chan, 6000);
06949 }
06950 if (!cmd) {
06951 retries++;
06952 }
06953 if (retries > 3) {
06954 cmd = '*';
06955 }
06956 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
06957 }
06958 }
06959
06960 if (msg_cfg)
06961 ast_config_destroy(msg_cfg);
06962 if (prepend_duration)
06963 *duration = prepend_duration;
06964
06965 if (already_recorded && cmd == -1) {
06966
06967 ast_filerename(backup, msgfile, NULL);
06968 rename(backup_textfile, textfile);
06969 }
06970
06971 if (cmd == 't' || cmd == 'S')
06972 cmd = 0;
06973 return cmd;
06974 }
06975
06976 static void queue_mwi_event(const char *box, int urgent, int new, int old)
06977 {
06978 struct ast_event *event;
06979 char *mailbox, *context;
06980
06981
06982 context = mailbox = ast_strdupa(box);
06983 strsep(&context, "@");
06984 if (ast_strlen_zero(context))
06985 context = "default";
06986
06987 if (!(event = ast_event_new(AST_EVENT_MWI,
06988 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
06989 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
06990 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
06991 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
06992 AST_EVENT_IE_END))) {
06993 return;
06994 }
06995
06996 ast_event_queue_and_cache(event);
06997 }
06998
06999
07000
07001
07002
07003
07004
07005
07006
07007
07008
07009
07010
07011
07012
07013 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)
07014 {
07015 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07016 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07017 const char *category;
07018 char *myserveremail = serveremail;
07019
07020 ast_channel_lock(chan);
07021 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07022 category = ast_strdupa(category);
07023 }
07024 ast_channel_unlock(chan);
07025
07026 #ifndef IMAP_STORAGE
07027 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07028 #else
07029 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07030 #endif
07031 make_file(fn, sizeof(fn), todir, msgnum);
07032 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07033
07034 if (!ast_strlen_zero(vmu->attachfmt)) {
07035 if (strstr(fmt, vmu->attachfmt))
07036 fmt = vmu->attachfmt;
07037 else
07038 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);
07039 }
07040
07041
07042 fmt = ast_strdupa(fmt);
07043 stringp = fmt;
07044 strsep(&stringp, "|");
07045
07046 if (!ast_strlen_zero(vmu->serveremail))
07047 myserveremail = vmu->serveremail;
07048
07049 if (!ast_strlen_zero(vmu->email)) {
07050 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07051
07052 if (attach_user_voicemail)
07053 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07054
07055
07056 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07057
07058 if (attach_user_voicemail)
07059 DISPOSE(todir, msgnum);
07060 }
07061
07062 if (!ast_strlen_zero(vmu->pager)) {
07063 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07064 }
07065
07066 if (ast_test_flag(vmu, VM_DELETE))
07067 DELETE(todir, msgnum, fn, vmu);
07068
07069
07070 if (ast_app_has_voicemail(ext_context, NULL))
07071 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07072
07073 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07074
07075 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);
07076 run_externnotify(vmu->context, vmu->mailbox, flag);
07077
07078 #ifdef IMAP_STORAGE
07079 vm_delete(fn);
07080 if (ast_test_flag(vmu, VM_DELETE)) {
07081 vm_imap_delete(NULL, vms->curmsg, vmu);
07082 vms->newmessages--;
07083 }
07084 #endif
07085
07086 return 0;
07087 }
07088
07089
07090
07091
07092
07093
07094
07095
07096
07097
07098
07099
07100
07101
07102
07103
07104
07105
07106
07107
07108
07109
07110
07111
07112
07113
07114
07115
07116 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)
07117 {
07118 #ifdef IMAP_STORAGE
07119 int todircount = 0;
07120 struct vm_state *dstvms;
07121 #endif
07122 char username[70]="";
07123 char fn[PATH_MAX];
07124 char ecodes[16] = "#";
07125 int res = 0, cmd = 0;
07126 struct ast_vm_user *receiver = NULL, *vmtmp;
07127 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07128 char *stringp;
07129 const char *s;
07130 int saved_messages = 0;
07131 int valid_extensions = 0;
07132 char *dir;
07133 int curmsg;
07134 char urgent_str[7] = "";
07135 int prompt_played = 0;
07136 #ifndef IMAP_STORAGE
07137 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07138 #endif
07139 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07140 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07141 }
07142
07143 if (vms == NULL) return -1;
07144 dir = vms->curdir;
07145 curmsg = vms->curmsg;
07146
07147 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07148 while (!res && !valid_extensions) {
07149 int use_directory = 0;
07150 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07151 int done = 0;
07152 int retries = 0;
07153 cmd = 0;
07154 while ((cmd >= 0) && !done ){
07155 if (cmd)
07156 retries = 0;
07157 switch (cmd) {
07158 case '1':
07159 use_directory = 0;
07160 done = 1;
07161 break;
07162 case '2':
07163 use_directory = 1;
07164 done = 1;
07165 break;
07166 case '*':
07167 cmd = 't';
07168 done = 1;
07169 break;
07170 default:
07171
07172 cmd = ast_play_and_wait(chan, "vm-forward");
07173 if (!cmd) {
07174 cmd = ast_waitfordigit(chan, 3000);
07175 }
07176 if (!cmd) {
07177 retries++;
07178 }
07179 if (retries > 3) {
07180 cmd = 't';
07181 done = 1;
07182 }
07183 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07184 }
07185 }
07186 if (cmd < 0 || cmd == 't')
07187 break;
07188 }
07189
07190 if (use_directory) {
07191
07192
07193 char old_context[sizeof(chan->context)];
07194 char old_exten[sizeof(chan->exten)];
07195 int old_priority;
07196 struct ast_app* directory_app;
07197
07198 directory_app = pbx_findapp("Directory");
07199 if (directory_app) {
07200 char vmcontext[256];
07201
07202 memcpy(old_context, chan->context, sizeof(chan->context));
07203 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07204 old_priority = chan->priority;
07205
07206
07207 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07208 res = pbx_exec(chan, directory_app, vmcontext);
07209
07210 ast_copy_string(username, chan->exten, sizeof(username));
07211
07212
07213 memcpy(chan->context, old_context, sizeof(chan->context));
07214 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07215 chan->priority = old_priority;
07216 } else {
07217 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07218 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07219 }
07220 } else {
07221
07222 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07223 res = ast_streamfile(chan, "vm-extension", chan->language);
07224 prompt_played++;
07225 if (res || prompt_played > 4)
07226 break;
07227 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07228 break;
07229 }
07230
07231
07232 if (ast_strlen_zero(username))
07233 continue;
07234 stringp = username;
07235 s = strsep(&stringp, "*");
07236
07237 valid_extensions = 1;
07238 while (s) {
07239 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07240 int oldmsgs;
07241 int newmsgs;
07242 int capacity;
07243 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07244 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07245
07246 res = ast_play_and_wait(chan, "pbx-invalid");
07247 valid_extensions = 0;
07248 break;
07249 }
07250 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07251 if ((newmsgs + oldmsgs) >= capacity) {
07252 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07253 res = ast_play_and_wait(chan, "vm-mailboxfull");
07254 valid_extensions = 0;
07255 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07256 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07257 free_user(vmtmp);
07258 }
07259 inprocess_count(receiver->mailbox, receiver->context, -1);
07260 break;
07261 }
07262 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07263 } else {
07264
07265
07266
07267
07268
07269 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07270 free_user(receiver);
07271 }
07272 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07273
07274 res = ast_play_and_wait(chan, "pbx-invalid");
07275 valid_extensions = 0;
07276 break;
07277 }
07278
07279
07280 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07281 RETRIEVE(fn, -1, s, receiver->context);
07282 if (ast_fileexists(fn, NULL, NULL) > 0) {
07283 res = ast_stream_and_wait(chan, fn, ecodes);
07284 if (res) {
07285 DISPOSE(fn, -1);
07286 return res;
07287 }
07288 } else {
07289 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07290 }
07291 DISPOSE(fn, -1);
07292
07293 s = strsep(&stringp, "*");
07294 }
07295
07296 if (valid_extensions)
07297 break;
07298 }
07299
07300 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07301 return res;
07302 if (is_new_message == 1) {
07303 struct leave_vm_options leave_options;
07304 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07305 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07306
07307
07308 memset(&leave_options, 0, sizeof(leave_options));
07309 leave_options.record_gain = record_gain;
07310 cmd = leave_voicemail(chan, mailbox, &leave_options);
07311 } else {
07312
07313 long duration = 0;
07314 struct vm_state vmstmp;
07315 int copy_msg_result = 0;
07316 memcpy(&vmstmp, vms, sizeof(vmstmp));
07317
07318 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07319
07320 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07321 if (!cmd) {
07322 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07323 #ifdef IMAP_STORAGE
07324 int attach_user_voicemail;
07325 char *myserveremail = serveremail;
07326
07327
07328 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07329 if (!dstvms) {
07330 dstvms = create_vm_state_from_user(vmtmp);
07331 }
07332 if (dstvms) {
07333 init_mailstream(dstvms, 0);
07334 if (!dstvms->mailstream) {
07335 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07336 } else {
07337 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07338 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07339 }
07340 } else {
07341 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07342 }
07343 if (!ast_strlen_zero(vmtmp->serveremail))
07344 myserveremail = vmtmp->serveremail;
07345 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07346
07347 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07348 dstvms->curbox,
07349 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07350 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07351 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07352 NULL, urgent_str);
07353 #else
07354 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07355 #endif
07356 saved_messages++;
07357 AST_LIST_REMOVE_CURRENT(list);
07358 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07359 free_user(vmtmp);
07360 if (res)
07361 break;
07362 }
07363 AST_LIST_TRAVERSE_SAFE_END;
07364 if (saved_messages > 0 && !copy_msg_result) {
07365
07366
07367
07368
07369
07370
07371
07372
07373 #ifdef IMAP_STORAGE
07374
07375 if (ast_strlen_zero(vmstmp.introfn))
07376 #endif
07377 res = ast_play_and_wait(chan, "vm-msgsaved");
07378 }
07379 #ifndef IMAP_STORAGE
07380 else {
07381
07382 res = ast_play_and_wait(chan, "vm-mailboxfull");
07383 }
07384
07385 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07386 strcpy(textfile, msgfile);
07387 strcpy(backup, msgfile);
07388 strcpy(backup_textfile, msgfile);
07389 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07390 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07391 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07392 if (ast_fileexists(backup, NULL, NULL) > 0) {
07393 ast_filerename(backup, msgfile, NULL);
07394 rename(backup_textfile, textfile);
07395 }
07396 #endif
07397 }
07398 DISPOSE(dir, curmsg);
07399 #ifndef IMAP_STORAGE
07400 if (cmd) {
07401 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07402 strcpy(textfile, msgfile);
07403 strcpy(backup_textfile, msgfile);
07404 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07405 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07406 rename(backup_textfile, textfile);
07407 }
07408 #endif
07409 }
07410
07411
07412 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07413 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07414 free_user(vmtmp);
07415 }
07416 return res ? res : cmd;
07417 }
07418
07419 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07420 {
07421 int res;
07422 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07423 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07424 return res;
07425 }
07426
07427 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07428 {
07429 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07430 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);
07431 }
07432
07433 static int play_message_category(struct ast_channel *chan, const char *category)
07434 {
07435 int res = 0;
07436
07437 if (!ast_strlen_zero(category))
07438 res = ast_play_and_wait(chan, category);
07439
07440 if (res) {
07441 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07442 res = 0;
07443 }
07444
07445 return res;
07446 }
07447
07448 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07449 {
07450 int res = 0;
07451 struct vm_zone *the_zone = NULL;
07452 time_t t;
07453
07454 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07455 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07456 return 0;
07457 }
07458
07459
07460 if (!ast_strlen_zero(vmu->zonetag)) {
07461
07462 struct vm_zone *z;
07463 AST_LIST_LOCK(&zones);
07464 AST_LIST_TRAVERSE(&zones, z, list) {
07465 if (!strcmp(z->name, vmu->zonetag)) {
07466 the_zone = z;
07467 break;
07468 }
07469 }
07470 AST_LIST_UNLOCK(&zones);
07471 }
07472
07473
07474 #if 0
07475
07476 ast_localtime(&t, &time_now, NULL);
07477 tv_now = ast_tvnow();
07478 ast_localtime(&tv_now, &time_then, NULL);
07479
07480
07481 if (time_now.tm_year == time_then.tm_year)
07482 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07483 else
07484 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07485 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07486
07487
07488 #endif
07489 if (the_zone) {
07490 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07491 } else if (!strncasecmp(chan->language, "de", 2)) {
07492 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07493 } else if (!strncasecmp(chan->language, "gr", 2)) {
07494 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07495 } else if (!strncasecmp(chan->language, "it", 2)) {
07496 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);
07497 } else if (!strncasecmp(chan->language, "nl", 2)) {
07498 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07499 } else if (!strncasecmp(chan->language, "no", 2)) {
07500 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07501 } else if (!strncasecmp(chan->language, "pl", 2)) {
07502 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07503 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07504 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);
07505 } else if (!strncasecmp(chan->language, "se", 2)) {
07506 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07507 } else if (!strncasecmp(chan->language, "zh", 2)) {
07508 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07509 } else if (!strncasecmp(chan->language, "vi", 2)) {
07510 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);
07511 } else {
07512 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07513 }
07514 #if 0
07515 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07516 #endif
07517 return res;
07518 }
07519
07520
07521
07522 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07523 {
07524 int res = 0;
07525 int i;
07526 char *callerid, *name;
07527 char prefile[PATH_MAX] = "";
07528
07529
07530
07531
07532
07533
07534
07535
07536
07537 if ((cid == NULL)||(context == NULL))
07538 return res;
07539
07540
07541 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07542 ast_callerid_parse(cid, &name, &callerid);
07543 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07544
07545
07546 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07547 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07548 if ((strcmp(cidinternalcontexts[i], context) == 0))
07549 break;
07550 }
07551 if (i != MAX_NUM_CID_CONTEXTS){
07552 if (!res) {
07553 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07554 if (!ast_strlen_zero(prefile)) {
07555
07556 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07557 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07558 if (!callback)
07559 res = wait_file2(chan, vms, "vm-from");
07560 res = ast_stream_and_wait(chan, prefile, "");
07561 } else {
07562 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07563
07564 if (!callback)
07565 res = wait_file2(chan, vms, "vm-from-extension");
07566 res = ast_say_digit_str(chan, callerid, "", chan->language);
07567 }
07568 }
07569 }
07570 } else if (!res) {
07571 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07572
07573 if (!callback)
07574 res = wait_file2(chan, vms, "vm-from-phonenumber");
07575 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07576 }
07577 } else {
07578
07579 ast_debug(1, "VM-CID: From an unknown number\n");
07580
07581 res = wait_file2(chan, vms, "vm-unknown-caller");
07582 }
07583 return res;
07584 }
07585
07586 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07587 {
07588 int res = 0;
07589 int durationm;
07590 int durations;
07591
07592 if (duration == NULL)
07593 return res;
07594
07595
07596 durations = atoi(duration);
07597 durationm = (durations / 60);
07598
07599 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07600
07601 if ((!res) && (durationm >= minduration)) {
07602 res = wait_file2(chan, vms, "vm-duration");
07603
07604
07605 if (!strncasecmp(chan->language, "pl", 2)) {
07606 div_t num = div(durationm, 10);
07607
07608 if (durationm == 1) {
07609 res = ast_play_and_wait(chan, "digits/1z");
07610 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07611 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07612 if (num.rem == 2) {
07613 if (!num.quot) {
07614 res = ast_play_and_wait(chan, "digits/2-ie");
07615 } else {
07616 res = say_and_wait(chan, durationm - 2 , chan->language);
07617 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07618 }
07619 } else {
07620 res = say_and_wait(chan, durationm, chan->language);
07621 }
07622 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07623 } else {
07624 res = say_and_wait(chan, durationm, chan->language);
07625 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07626 }
07627
07628 } else {
07629 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07630 res = wait_file2(chan, vms, "vm-minutes");
07631 }
07632 }
07633 return res;
07634 }
07635
07636 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07637 {
07638 int res = 0;
07639 char filename[256], *cid;
07640 const char *origtime, *context, *category, *duration, *flag;
07641 struct ast_config *msg_cfg;
07642 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07643
07644 vms->starting = 0;
07645 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07646 adsi_message(chan, vms);
07647 if (!vms->curmsg) {
07648 res = wait_file2(chan, vms, "vm-first");
07649 } else if (vms->curmsg == vms->lastmsg) {
07650 res = wait_file2(chan, vms, "vm-last");
07651 }
07652
07653 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07654 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07655 msg_cfg = ast_config_load(filename, config_flags);
07656 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07657 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07658 return 0;
07659 }
07660 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07661
07662
07663 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07664 res = wait_file2(chan, vms, "vm-Urgent");
07665 }
07666
07667 if (!res) {
07668
07669
07670 if (!strncasecmp(chan->language, "pl", 2)) {
07671 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07672 int ten, one;
07673 char nextmsg[256];
07674 ten = (vms->curmsg + 1) / 10;
07675 one = (vms->curmsg + 1) % 10;
07676
07677 if (vms->curmsg < 20) {
07678 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07679 res = wait_file2(chan, vms, nextmsg);
07680 } else {
07681 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07682 res = wait_file2(chan, vms, nextmsg);
07683 if (one > 0) {
07684 if (!res) {
07685 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07686 res = wait_file2(chan, vms, nextmsg);
07687 }
07688 }
07689 }
07690 }
07691 if (!res)
07692 res = wait_file2(chan, vms, "vm-message");
07693
07694 } else if (!strncasecmp(chan->language, "he", 2)) {
07695 if (!vms->curmsg) {
07696 res = wait_file2(chan, vms, "vm-message");
07697 res = wait_file2(chan, vms, "vm-first");
07698 } else if (vms->curmsg == vms->lastmsg) {
07699 res = wait_file2(chan, vms, "vm-message");
07700 res = wait_file2(chan, vms, "vm-last");
07701 } else {
07702 res = wait_file2(chan, vms, "vm-message");
07703 res = wait_file2(chan, vms, "vm-number");
07704 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07705 }
07706
07707 } else if (!strncasecmp(chan->language, "vi", 2)) {
07708 if (!vms->curmsg) {
07709 res = wait_file2(chan, vms, "vm-message");
07710 res = wait_file2(chan, vms, "vm-first");
07711 } else if (vms->curmsg == vms->lastmsg) {
07712 res = wait_file2(chan, vms, "vm-message");
07713 res = wait_file2(chan, vms, "vm-last");
07714 } else {
07715 res = wait_file2(chan, vms, "vm-message");
07716 res = wait_file2(chan, vms, "vm-number");
07717 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07718 }
07719 } else {
07720 if (!strncasecmp(chan->language, "se", 2)) {
07721 res = wait_file2(chan, vms, "vm-meddelandet");
07722 } else {
07723 res = wait_file2(chan, vms, "vm-message");
07724 }
07725 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07726 if (!res) {
07727 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07728 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07729 }
07730 }
07731 }
07732 }
07733
07734 if (!msg_cfg) {
07735 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07736 return 0;
07737 }
07738
07739 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07740 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07741 DISPOSE(vms->curdir, vms->curmsg);
07742 ast_config_destroy(msg_cfg);
07743 return 0;
07744 }
07745
07746 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07747 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07748 category = ast_variable_retrieve(msg_cfg, "message", "category");
07749
07750 context = ast_variable_retrieve(msg_cfg, "message", "context");
07751 if (!strncasecmp("macro", context, 5))
07752 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07753 if (!res) {
07754 res = play_message_category(chan, category);
07755 }
07756 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07757 res = play_message_datetime(chan, vmu, origtime, filename);
07758 }
07759 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07760 res = play_message_callerid(chan, vms, cid, context, 0);
07761 }
07762 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07763 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07764 }
07765
07766 if (res == '1') {
07767 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07768 res = 0;
07769 }
07770 ast_config_destroy(msg_cfg);
07771
07772 if (!res) {
07773 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07774 vms->heard[vms->curmsg] = 1;
07775 #ifdef IMAP_STORAGE
07776
07777
07778
07779 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07780 wait_file(chan, vms, vms->introfn);
07781 }
07782 #endif
07783 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07784 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07785 res = 0;
07786 }
07787 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07788 }
07789 DISPOSE(vms->curdir, vms->curmsg);
07790 return res;
07791 }
07792
07793 #ifdef IMAP_STORAGE
07794 static int imap_remove_file(char *dir, int msgnum)
07795 {
07796 char fn[PATH_MAX];
07797 char full_fn[PATH_MAX];
07798 char intro[PATH_MAX] = {0,};
07799
07800 if (msgnum > -1) {
07801 make_file(fn, sizeof(fn), dir, msgnum);
07802 snprintf(intro, sizeof(intro), "%sintro", fn);
07803 } else
07804 ast_copy_string(fn, dir, sizeof(fn));
07805
07806 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07807 ast_filedelete(fn, NULL);
07808 if (!ast_strlen_zero(intro)) {
07809 ast_filedelete(intro, NULL);
07810 }
07811 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07812 unlink(full_fn);
07813 }
07814 return 0;
07815 }
07816
07817
07818
07819 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07820 {
07821 char *file, *filename;
07822 char *attachment;
07823 char arg[10];
07824 int i;
07825 BODY* body;
07826
07827 file = strrchr(ast_strdupa(dir), '/');
07828 if (file) {
07829 *file++ = '\0';
07830 } else {
07831 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07832 return -1;
07833 }
07834
07835 ast_mutex_lock(&vms->lock);
07836 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07837 mail_fetchstructure(vms->mailstream, i + 1, &body);
07838
07839 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07840 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07841 } else {
07842 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07843 ast_mutex_unlock(&vms->lock);
07844 return -1;
07845 }
07846 filename = strsep(&attachment, ".");
07847 if (!strcmp(filename, file)) {
07848 sprintf(arg, "%d", i + 1);
07849 mail_setflag(vms->mailstream, arg, "\\DELETED");
07850 }
07851 }
07852 mail_expunge(vms->mailstream);
07853 ast_mutex_unlock(&vms->lock);
07854 return 0;
07855 }
07856
07857 #elif !defined(IMAP_STORAGE)
07858 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07859 {
07860 int count_msg, last_msg;
07861
07862 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07863
07864
07865
07866
07867 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07868
07869
07870 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07871
07872
07873 count_msg = count_messages(vmu, vms->curdir);
07874 if (count_msg < 0) {
07875 return count_msg;
07876 } else {
07877 vms->lastmsg = count_msg - 1;
07878 }
07879
07880 if (vm_allocate_dh(vms, vmu, count_msg)) {
07881 return -1;
07882 }
07883
07884
07885
07886
07887
07888
07889
07890
07891 if (vm_lock_path(vms->curdir)) {
07892 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07893 return ERROR_LOCK_PATH;
07894 }
07895
07896
07897 last_msg = last_message_index(vmu, vms->curdir);
07898 ast_unlock_path(vms->curdir);
07899
07900 if (last_msg < -1) {
07901 return last_msg;
07902 } else if (vms->lastmsg != last_msg) {
07903 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);
07904 resequence_mailbox(vmu, vms->curdir, count_msg);
07905 }
07906
07907 return 0;
07908 }
07909 #endif
07910
07911 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07912 {
07913 int x = 0;
07914
07915 #ifndef IMAP_STORAGE
07916 int last_msg_idx;
07917 int res = 0, nummsg;
07918 char fn2[PATH_MAX];
07919 #endif
07920
07921 if (vms->lastmsg <= -1) {
07922 goto done;
07923 }
07924
07925 vms->curmsg = -1;
07926 #ifndef IMAP_STORAGE
07927
07928 if (vm_lock_path(vms->curdir)) {
07929 return ERROR_LOCK_PATH;
07930 }
07931
07932
07933 last_msg_idx = last_message_index(vmu, vms->curdir);
07934 if (last_msg_idx != vms->lastmsg) {
07935 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
07936 }
07937
07938
07939 for (x = 0; x < last_msg_idx + 1; x++) {
07940 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07941
07942 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07943 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07944 break;
07945 }
07946 vms->curmsg++;
07947 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07948 if (strcmp(vms->fn, fn2)) {
07949 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07950 }
07951 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07952
07953 res = save_to_folder(vmu, vms, x, 1);
07954 if (res == ERROR_LOCK_PATH) {
07955
07956 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07957 vms->deleted[x] = 0;
07958 vms->heard[x] = 0;
07959 --x;
07960 }
07961 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07962
07963 res = save_to_folder(vmu, vms, x, 10);
07964 if (res == ERROR_LOCK_PATH) {
07965
07966 vms->deleted[x] = 0;
07967 vms->heard[x] = 0;
07968 --x;
07969 }
07970 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07971
07972
07973 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07974 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07975 DELETE(vms->curdir, x, vms->fn, vmu);
07976 }
07977 }
07978 }
07979
07980
07981 nummsg = x - 1;
07982 for (x = vms->curmsg + 1; x <= nummsg; x++) {
07983 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07984 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07985 DELETE(vms->curdir, x, vms->fn, vmu);
07986 }
07987 }
07988 ast_unlock_path(vms->curdir);
07989 #else
07990 if (vms->deleted) {
07991
07992
07993 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
07994 if (vms->deleted[x]) {
07995 ast_debug(3, "IMAP delete of %d\n", x);
07996 DELETE(vms->curdir, x, vms->fn, vmu);
07997 }
07998 }
07999 }
08000 #endif
08001
08002 done:
08003 if (vms->deleted && vmu->maxmsg) {
08004 memset(vms->deleted, 0, vms->dh_arraysize * sizeof(int));
08005 }
08006 if (vms->heard && vmu->maxmsg) {
08007 memset(vms->heard, 0, vms->dh_arraysize * sizeof(int));
08008 }
08009
08010 return 0;
08011 }
08012
08013
08014
08015
08016
08017
08018
08019 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08020 {
08021 int cmd;
08022 char *buf;
08023
08024 buf = alloca(strlen(box) + 2);
08025 strcpy(buf, box);
08026 strcat(buf, "s");
08027
08028 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08029 cmd = ast_play_and_wait(chan, buf);
08030 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08031 } else {
08032 cmd = ast_play_and_wait(chan, "vm-messages");
08033 return cmd ? cmd : ast_play_and_wait(chan, box);
08034 }
08035 }
08036
08037 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08038 {
08039 int cmd;
08040
08041 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08042 if (!strcasecmp(box, "vm-INBOX"))
08043 cmd = ast_play_and_wait(chan, "vm-new-e");
08044 else
08045 cmd = ast_play_and_wait(chan, "vm-old-e");
08046 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08047 } else {
08048 cmd = ast_play_and_wait(chan, "vm-messages");
08049 return cmd ? cmd : ast_play_and_wait(chan, box);
08050 }
08051 }
08052
08053 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08054 {
08055 int cmd;
08056
08057 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08058 cmd = ast_play_and_wait(chan, "vm-messages");
08059 return cmd ? cmd : ast_play_and_wait(chan, box);
08060 } else {
08061 cmd = ast_play_and_wait(chan, box);
08062 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08063 }
08064 }
08065
08066 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08067 {
08068 int cmd;
08069
08070 if ( !strncasecmp(chan->language, "it", 2) ||
08071 !strncasecmp(chan->language, "es", 2) ||
08072 !strncasecmp(chan->language, "pt", 2)) {
08073 cmd = ast_play_and_wait(chan, "vm-messages");
08074 return cmd ? cmd : ast_play_and_wait(chan, box);
08075 } else if (!strncasecmp(chan->language, "gr", 2)) {
08076 return vm_play_folder_name_gr(chan, box);
08077 } else if (!strncasecmp(chan->language, "he", 2)) {
08078 return ast_play_and_wait(chan, box);
08079 } else if (!strncasecmp(chan->language, "pl", 2)) {
08080 return vm_play_folder_name_pl(chan, box);
08081 } else if (!strncasecmp(chan->language, "ua", 2)) {
08082 return vm_play_folder_name_ua(chan, box);
08083 } else if (!strncasecmp(chan->language, "vi", 2)) {
08084 return ast_play_and_wait(chan, box);
08085 } else {
08086 cmd = ast_play_and_wait(chan, box);
08087 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08088 }
08089 }
08090
08091
08092
08093
08094
08095
08096
08097
08098
08099
08100
08101
08102
08103 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08104 {
08105 int res = 0;
08106
08107 if (vms->newmessages) {
08108 res = ast_play_and_wait(chan, "vm-youhave");
08109 if (!res)
08110 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08111 if (!res) {
08112 if ((vms->newmessages == 1)) {
08113 res = ast_play_and_wait(chan, "vm-INBOX");
08114 if (!res)
08115 res = ast_play_and_wait(chan, "vm-message");
08116 } else {
08117 res = ast_play_and_wait(chan, "vm-INBOXs");
08118 if (!res)
08119 res = ast_play_and_wait(chan, "vm-messages");
08120 }
08121 }
08122 } else if (vms->oldmessages){
08123 res = ast_play_and_wait(chan, "vm-youhave");
08124 if (!res)
08125 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08126 if ((vms->oldmessages == 1)){
08127 res = ast_play_and_wait(chan, "vm-Old");
08128 if (!res)
08129 res = ast_play_and_wait(chan, "vm-message");
08130 } else {
08131 res = ast_play_and_wait(chan, "vm-Olds");
08132 if (!res)
08133 res = ast_play_and_wait(chan, "vm-messages");
08134 }
08135 } else if (!vms->oldmessages && !vms->newmessages)
08136 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08137 return res;
08138 }
08139
08140
08141
08142
08143
08144
08145
08146
08147
08148
08149
08150
08151
08152
08153
08154
08155
08156
08157
08158
08159
08160
08161
08162
08163
08164
08165
08166
08167
08168
08169
08170
08171
08172
08173
08174
08175
08176
08177
08178
08179
08180
08181
08182
08183
08184
08185
08186
08187
08188
08189
08190
08191
08192
08193
08194
08195
08196
08197 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08198 {
08199 int res;
08200 int lastnum = 0;
08201
08202 res = ast_play_and_wait(chan, "vm-youhave");
08203
08204 if (!res && vms->newmessages) {
08205 lastnum = vms->newmessages;
08206
08207 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08208 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08209 }
08210
08211 if (!res && vms->oldmessages) {
08212 res = ast_play_and_wait(chan, "vm-and");
08213 }
08214 }
08215
08216 if (!res && vms->oldmessages) {
08217 lastnum = vms->oldmessages;
08218
08219 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08220 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08221 }
08222 }
08223
08224 if (!res) {
08225 if (lastnum == 0) {
08226 res = ast_play_and_wait(chan, "vm-no");
08227 }
08228 if (!res) {
08229 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08230 }
08231 }
08232
08233 return res;
08234 }
08235
08236
08237 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08238 {
08239 int res = 0;
08240
08241
08242 if (!res) {
08243 if ((vms->newmessages) || (vms->oldmessages)) {
08244 res = ast_play_and_wait(chan, "vm-youhave");
08245 }
08246
08247
08248
08249
08250
08251 if (vms->newmessages) {
08252 if (!res) {
08253 if (vms->newmessages == 1) {
08254 res = ast_play_and_wait(chan, "vm-INBOX1");
08255 } else {
08256 if (vms->newmessages == 2) {
08257 res = ast_play_and_wait(chan, "vm-shtei");
08258 } else {
08259 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08260 }
08261 res = ast_play_and_wait(chan, "vm-INBOX");
08262 }
08263 }
08264 if (vms->oldmessages && !res) {
08265 res = ast_play_and_wait(chan, "vm-and");
08266 if (vms->oldmessages == 1) {
08267 res = ast_play_and_wait(chan, "vm-Old1");
08268 } else {
08269 if (vms->oldmessages == 2) {
08270 res = ast_play_and_wait(chan, "vm-shtei");
08271 } else {
08272 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08273 }
08274 res = ast_play_and_wait(chan, "vm-Old");
08275 }
08276 }
08277 }
08278 if (!res && vms->oldmessages && !vms->newmessages) {
08279 if (!res) {
08280 if (vms->oldmessages == 1) {
08281 res = ast_play_and_wait(chan, "vm-Old1");
08282 } else {
08283 if (vms->oldmessages == 2) {
08284 res = ast_play_and_wait(chan, "vm-shtei");
08285 } else {
08286 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08287 }
08288 res = ast_play_and_wait(chan, "vm-Old");
08289 }
08290 }
08291 }
08292 if (!res) {
08293 if (!vms->oldmessages && !vms->newmessages) {
08294 if (!res) {
08295 res = ast_play_and_wait(chan, "vm-nomessages");
08296 }
08297 }
08298 }
08299 }
08300 return res;
08301 }
08302
08303
08304 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08305 {
08306 int res;
08307
08308
08309 res = ast_play_and_wait(chan, "vm-youhave");
08310 if (!res) {
08311 if (vms->urgentmessages) {
08312 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08313 if (!res)
08314 res = ast_play_and_wait(chan, "vm-Urgent");
08315 if ((vms->oldmessages || vms->newmessages) && !res) {
08316 res = ast_play_and_wait(chan, "vm-and");
08317 } else if (!res) {
08318 if ((vms->urgentmessages == 1))
08319 res = ast_play_and_wait(chan, "vm-message");
08320 else
08321 res = ast_play_and_wait(chan, "vm-messages");
08322 }
08323 }
08324 if (vms->newmessages) {
08325 res = say_and_wait(chan, vms->newmessages, chan->language);
08326 if (!res)
08327 res = ast_play_and_wait(chan, "vm-INBOX");
08328 if (vms->oldmessages && !res)
08329 res = ast_play_and_wait(chan, "vm-and");
08330 else if (!res) {
08331 if ((vms->newmessages == 1))
08332 res = ast_play_and_wait(chan, "vm-message");
08333 else
08334 res = ast_play_and_wait(chan, "vm-messages");
08335 }
08336
08337 }
08338 if (!res && vms->oldmessages) {
08339 res = say_and_wait(chan, vms->oldmessages, chan->language);
08340 if (!res)
08341 res = ast_play_and_wait(chan, "vm-Old");
08342 if (!res) {
08343 if (vms->oldmessages == 1)
08344 res = ast_play_and_wait(chan, "vm-message");
08345 else
08346 res = ast_play_and_wait(chan, "vm-messages");
08347 }
08348 }
08349 if (!res) {
08350 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08351 res = ast_play_and_wait(chan, "vm-no");
08352 if (!res)
08353 res = ast_play_and_wait(chan, "vm-messages");
08354 }
08355 }
08356 }
08357 return res;
08358 }
08359
08360
08361 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08362 {
08363
08364 int res;
08365 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08366 res = ast_play_and_wait(chan, "vm-no") ||
08367 ast_play_and_wait(chan, "vm-message");
08368 else
08369 res = ast_play_and_wait(chan, "vm-youhave");
08370 if (!res && vms->newmessages) {
08371 res = (vms->newmessages == 1) ?
08372 ast_play_and_wait(chan, "digits/un") ||
08373 ast_play_and_wait(chan, "vm-nuovo") ||
08374 ast_play_and_wait(chan, "vm-message") :
08375
08376 say_and_wait(chan, vms->newmessages, chan->language) ||
08377 ast_play_and_wait(chan, "vm-nuovi") ||
08378 ast_play_and_wait(chan, "vm-messages");
08379 if (!res && vms->oldmessages)
08380 res = ast_play_and_wait(chan, "vm-and");
08381 }
08382 if (!res && vms->oldmessages) {
08383 res = (vms->oldmessages == 1) ?
08384 ast_play_and_wait(chan, "digits/un") ||
08385 ast_play_and_wait(chan, "vm-vecchio") ||
08386 ast_play_and_wait(chan, "vm-message") :
08387
08388 say_and_wait(chan, vms->oldmessages, chan->language) ||
08389 ast_play_and_wait(chan, "vm-vecchi") ||
08390 ast_play_and_wait(chan, "vm-messages");
08391 }
08392 return res;
08393 }
08394
08395
08396 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08397 {
08398
08399 int res;
08400 div_t num;
08401
08402 if (!vms->oldmessages && !vms->newmessages) {
08403 res = ast_play_and_wait(chan, "vm-no");
08404 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08405 return res;
08406 } else {
08407 res = ast_play_and_wait(chan, "vm-youhave");
08408 }
08409
08410 if (vms->newmessages) {
08411 num = div(vms->newmessages, 10);
08412 if (vms->newmessages == 1) {
08413 res = ast_play_and_wait(chan, "digits/1-a");
08414 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08415 res = res ? res : ast_play_and_wait(chan, "vm-message");
08416 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08417 if (num.rem == 2) {
08418 if (!num.quot) {
08419 res = ast_play_and_wait(chan, "digits/2-ie");
08420 } else {
08421 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08422 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08423 }
08424 } else {
08425 res = say_and_wait(chan, vms->newmessages, chan->language);
08426 }
08427 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08428 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08429 } else {
08430 res = say_and_wait(chan, vms->newmessages, chan->language);
08431 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08432 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08433 }
08434 if (!res && vms->oldmessages)
08435 res = ast_play_and_wait(chan, "vm-and");
08436 }
08437 if (!res && vms->oldmessages) {
08438 num = div(vms->oldmessages, 10);
08439 if (vms->oldmessages == 1) {
08440 res = ast_play_and_wait(chan, "digits/1-a");
08441 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08442 res = res ? res : ast_play_and_wait(chan, "vm-message");
08443 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08444 if (num.rem == 2) {
08445 if (!num.quot) {
08446 res = ast_play_and_wait(chan, "digits/2-ie");
08447 } else {
08448 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08449 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08450 }
08451 } else {
08452 res = say_and_wait(chan, vms->oldmessages, chan->language);
08453 }
08454 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08455 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08456 } else {
08457 res = say_and_wait(chan, vms->oldmessages, chan->language);
08458 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08459 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08460 }
08461 }
08462
08463 return res;
08464 }
08465
08466
08467 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08468 {
08469
08470 int res;
08471
08472 res = ast_play_and_wait(chan, "vm-youhave");
08473 if (res)
08474 return res;
08475
08476 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08477 res = ast_play_and_wait(chan, "vm-no");
08478 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08479 return res;
08480 }
08481
08482 if (vms->newmessages) {
08483 if ((vms->newmessages == 1)) {
08484 res = ast_play_and_wait(chan, "digits/ett");
08485 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08486 res = res ? res : ast_play_and_wait(chan, "vm-message");
08487 } else {
08488 res = say_and_wait(chan, vms->newmessages, chan->language);
08489 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08490 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08491 }
08492 if (!res && vms->oldmessages)
08493 res = ast_play_and_wait(chan, "vm-and");
08494 }
08495 if (!res && vms->oldmessages) {
08496 if (vms->oldmessages == 1) {
08497 res = ast_play_and_wait(chan, "digits/ett");
08498 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08499 res = res ? res : ast_play_and_wait(chan, "vm-message");
08500 } else {
08501 res = say_and_wait(chan, vms->oldmessages, chan->language);
08502 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08503 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08504 }
08505 }
08506
08507 return res;
08508 }
08509
08510
08511 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08512 {
08513
08514 int res;
08515
08516 res = ast_play_and_wait(chan, "vm-youhave");
08517 if (res)
08518 return res;
08519
08520 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08521 res = ast_play_and_wait(chan, "vm-no");
08522 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08523 return res;
08524 }
08525
08526 if (vms->newmessages) {
08527 if ((vms->newmessages == 1)) {
08528 res = ast_play_and_wait(chan, "digits/1");
08529 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08530 res = res ? res : ast_play_and_wait(chan, "vm-message");
08531 } else {
08532 res = say_and_wait(chan, vms->newmessages, chan->language);
08533 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08534 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08535 }
08536 if (!res && vms->oldmessages)
08537 res = ast_play_and_wait(chan, "vm-and");
08538 }
08539 if (!res && vms->oldmessages) {
08540 if (vms->oldmessages == 1) {
08541 res = ast_play_and_wait(chan, "digits/1");
08542 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08543 res = res ? res : ast_play_and_wait(chan, "vm-message");
08544 } else {
08545 res = say_and_wait(chan, vms->oldmessages, chan->language);
08546 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08547 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08548 }
08549 }
08550
08551 return res;
08552 }
08553
08554
08555 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08556 {
08557
08558 int res;
08559 res = ast_play_and_wait(chan, "vm-youhave");
08560 if (!res) {
08561 if (vms->newmessages) {
08562 if ((vms->newmessages == 1))
08563 res = ast_play_and_wait(chan, "digits/1F");
08564 else
08565 res = say_and_wait(chan, vms->newmessages, chan->language);
08566 if (!res)
08567 res = ast_play_and_wait(chan, "vm-INBOX");
08568 if (vms->oldmessages && !res)
08569 res = ast_play_and_wait(chan, "vm-and");
08570 else if (!res) {
08571 if ((vms->newmessages == 1))
08572 res = ast_play_and_wait(chan, "vm-message");
08573 else
08574 res = ast_play_and_wait(chan, "vm-messages");
08575 }
08576
08577 }
08578 if (!res && vms->oldmessages) {
08579 if (vms->oldmessages == 1)
08580 res = ast_play_and_wait(chan, "digits/1F");
08581 else
08582 res = say_and_wait(chan, vms->oldmessages, chan->language);
08583 if (!res)
08584 res = ast_play_and_wait(chan, "vm-Old");
08585 if (!res) {
08586 if (vms->oldmessages == 1)
08587 res = ast_play_and_wait(chan, "vm-message");
08588 else
08589 res = ast_play_and_wait(chan, "vm-messages");
08590 }
08591 }
08592 if (!res) {
08593 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08594 res = ast_play_and_wait(chan, "vm-no");
08595 if (!res)
08596 res = ast_play_and_wait(chan, "vm-messages");
08597 }
08598 }
08599 }
08600 return res;
08601 }
08602
08603
08604 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08605 {
08606
08607 int res;
08608 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08609 res = ast_play_and_wait(chan, "vm-youhaveno");
08610 if (!res)
08611 res = ast_play_and_wait(chan, "vm-messages");
08612 } else {
08613 res = ast_play_and_wait(chan, "vm-youhave");
08614 }
08615 if (!res) {
08616 if (vms->newmessages) {
08617 if (!res) {
08618 if ((vms->newmessages == 1)) {
08619 res = ast_play_and_wait(chan, "digits/1M");
08620 if (!res)
08621 res = ast_play_and_wait(chan, "vm-message");
08622 if (!res)
08623 res = ast_play_and_wait(chan, "vm-INBOXs");
08624 } else {
08625 res = say_and_wait(chan, vms->newmessages, chan->language);
08626 if (!res)
08627 res = ast_play_and_wait(chan, "vm-messages");
08628 if (!res)
08629 res = ast_play_and_wait(chan, "vm-INBOX");
08630 }
08631 }
08632 if (vms->oldmessages && !res)
08633 res = ast_play_and_wait(chan, "vm-and");
08634 }
08635 if (vms->oldmessages) {
08636 if (!res) {
08637 if (vms->oldmessages == 1) {
08638 res = ast_play_and_wait(chan, "digits/1M");
08639 if (!res)
08640 res = ast_play_and_wait(chan, "vm-message");
08641 if (!res)
08642 res = ast_play_and_wait(chan, "vm-Olds");
08643 } else {
08644 res = say_and_wait(chan, vms->oldmessages, chan->language);
08645 if (!res)
08646 res = ast_play_and_wait(chan, "vm-messages");
08647 if (!res)
08648 res = ast_play_and_wait(chan, "vm-Old");
08649 }
08650 }
08651 }
08652 }
08653 return res;
08654 }
08655
08656
08657 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08658
08659 int res;
08660 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08661 res = ast_play_and_wait(chan, "vm-nomessages");
08662 return res;
08663 } else {
08664 res = ast_play_and_wait(chan, "vm-youhave");
08665 }
08666 if (vms->newmessages) {
08667 if (!res)
08668 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08669 if ((vms->newmessages == 1)) {
08670 if (!res)
08671 res = ast_play_and_wait(chan, "vm-message");
08672 if (!res)
08673 res = ast_play_and_wait(chan, "vm-INBOXs");
08674 } else {
08675 if (!res)
08676 res = ast_play_and_wait(chan, "vm-messages");
08677 if (!res)
08678 res = ast_play_and_wait(chan, "vm-INBOX");
08679 }
08680 if (vms->oldmessages && !res)
08681 res = ast_play_and_wait(chan, "vm-and");
08682 }
08683 if (vms->oldmessages) {
08684 if (!res)
08685 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08686 if (vms->oldmessages == 1) {
08687 if (!res)
08688 res = ast_play_and_wait(chan, "vm-message");
08689 if (!res)
08690 res = ast_play_and_wait(chan, "vm-Olds");
08691 } else {
08692 if (!res)
08693 res = ast_play_and_wait(chan, "vm-messages");
08694 if (!res)
08695 res = ast_play_and_wait(chan, "vm-Old");
08696 }
08697 }
08698 return res;
08699 }
08700
08701
08702 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08703 {
08704
08705 int res;
08706 res = ast_play_and_wait(chan, "vm-youhave");
08707 if (!res) {
08708 if (vms->newmessages) {
08709 res = say_and_wait(chan, vms->newmessages, chan->language);
08710 if (!res)
08711 res = ast_play_and_wait(chan, "vm-INBOX");
08712 if (vms->oldmessages && !res)
08713 res = ast_play_and_wait(chan, "vm-and");
08714 else if (!res) {
08715 if ((vms->newmessages == 1))
08716 res = ast_play_and_wait(chan, "vm-message");
08717 else
08718 res = ast_play_and_wait(chan, "vm-messages");
08719 }
08720
08721 }
08722 if (!res && vms->oldmessages) {
08723 res = say_and_wait(chan, vms->oldmessages, chan->language);
08724 if (!res)
08725 res = ast_play_and_wait(chan, "vm-Old");
08726 if (!res) {
08727 if (vms->oldmessages == 1)
08728 res = ast_play_and_wait(chan, "vm-message");
08729 else
08730 res = ast_play_and_wait(chan, "vm-messages");
08731 }
08732 }
08733 if (!res) {
08734 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08735 res = ast_play_and_wait(chan, "vm-no");
08736 if (!res)
08737 res = ast_play_and_wait(chan, "vm-messages");
08738 }
08739 }
08740 }
08741 return res;
08742 }
08743
08744
08745 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08746 {
08747
08748 int res;
08749 res = ast_play_and_wait(chan, "vm-youhave");
08750 if (!res) {
08751 if (vms->newmessages) {
08752 res = say_and_wait(chan, vms->newmessages, chan->language);
08753 if (!res) {
08754 if (vms->newmessages == 1)
08755 res = ast_play_and_wait(chan, "vm-INBOXs");
08756 else
08757 res = ast_play_and_wait(chan, "vm-INBOX");
08758 }
08759 if (vms->oldmessages && !res)
08760 res = ast_play_and_wait(chan, "vm-and");
08761 else if (!res) {
08762 if ((vms->newmessages == 1))
08763 res = ast_play_and_wait(chan, "vm-message");
08764 else
08765 res = ast_play_and_wait(chan, "vm-messages");
08766 }
08767
08768 }
08769 if (!res && vms->oldmessages) {
08770 res = say_and_wait(chan, vms->oldmessages, chan->language);
08771 if (!res) {
08772 if (vms->oldmessages == 1)
08773 res = ast_play_and_wait(chan, "vm-Olds");
08774 else
08775 res = ast_play_and_wait(chan, "vm-Old");
08776 }
08777 if (!res) {
08778 if (vms->oldmessages == 1)
08779 res = ast_play_and_wait(chan, "vm-message");
08780 else
08781 res = ast_play_and_wait(chan, "vm-messages");
08782 }
08783 }
08784 if (!res) {
08785 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08786 res = ast_play_and_wait(chan, "vm-no");
08787 if (!res)
08788 res = ast_play_and_wait(chan, "vm-messages");
08789 }
08790 }
08791 }
08792 return res;
08793 }
08794
08795
08796 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08797 {
08798
08799 int res;
08800 res = ast_play_and_wait(chan, "vm-youhave");
08801 if (!res) {
08802 if (vms->newmessages) {
08803 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08804 if (!res) {
08805 if ((vms->newmessages == 1)) {
08806 res = ast_play_and_wait(chan, "vm-message");
08807 if (!res)
08808 res = ast_play_and_wait(chan, "vm-INBOXs");
08809 } else {
08810 res = ast_play_and_wait(chan, "vm-messages");
08811 if (!res)
08812 res = ast_play_and_wait(chan, "vm-INBOX");
08813 }
08814 }
08815 if (vms->oldmessages && !res)
08816 res = ast_play_and_wait(chan, "vm-and");
08817 }
08818 if (!res && vms->oldmessages) {
08819 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08820 if (!res) {
08821 if (vms->oldmessages == 1) {
08822 res = ast_play_and_wait(chan, "vm-message");
08823 if (!res)
08824 res = ast_play_and_wait(chan, "vm-Olds");
08825 } else {
08826 res = ast_play_and_wait(chan, "vm-messages");
08827 if (!res)
08828 res = ast_play_and_wait(chan, "vm-Old");
08829 }
08830 }
08831 }
08832 if (!res) {
08833 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08834 res = ast_play_and_wait(chan, "vm-no");
08835 if (!res)
08836 res = ast_play_and_wait(chan, "vm-messages");
08837 }
08838 }
08839 }
08840 return res;
08841 }
08842
08843
08844
08845
08846
08847
08848
08849
08850
08851
08852
08853
08854
08855
08856
08857
08858
08859 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08860 {
08861 int res;
08862 res = ast_play_and_wait(chan, "vm-youhave");
08863 if (!res) {
08864 if (vms->newmessages) {
08865 if (vms->newmessages == 1) {
08866 res = ast_play_and_wait(chan, "digits/jednu");
08867 } else {
08868 res = say_and_wait(chan, vms->newmessages, chan->language);
08869 }
08870 if (!res) {
08871 if ((vms->newmessages == 1))
08872 res = ast_play_and_wait(chan, "vm-novou");
08873 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08874 res = ast_play_and_wait(chan, "vm-nove");
08875 if (vms->newmessages > 4)
08876 res = ast_play_and_wait(chan, "vm-novych");
08877 }
08878 if (vms->oldmessages && !res)
08879 res = ast_play_and_wait(chan, "vm-and");
08880 else if (!res) {
08881 if ((vms->newmessages == 1))
08882 res = ast_play_and_wait(chan, "vm-zpravu");
08883 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08884 res = ast_play_and_wait(chan, "vm-zpravy");
08885 if (vms->newmessages > 4)
08886 res = ast_play_and_wait(chan, "vm-zprav");
08887 }
08888 }
08889 if (!res && vms->oldmessages) {
08890 res = say_and_wait(chan, vms->oldmessages, chan->language);
08891 if (!res) {
08892 if ((vms->oldmessages == 1))
08893 res = ast_play_and_wait(chan, "vm-starou");
08894 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08895 res = ast_play_and_wait(chan, "vm-stare");
08896 if (vms->oldmessages > 4)
08897 res = ast_play_and_wait(chan, "vm-starych");
08898 }
08899 if (!res) {
08900 if ((vms->oldmessages == 1))
08901 res = ast_play_and_wait(chan, "vm-zpravu");
08902 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08903 res = ast_play_and_wait(chan, "vm-zpravy");
08904 if (vms->oldmessages > 4)
08905 res = ast_play_and_wait(chan, "vm-zprav");
08906 }
08907 }
08908 if (!res) {
08909 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08910 res = ast_play_and_wait(chan, "vm-no");
08911 if (!res)
08912 res = ast_play_and_wait(chan, "vm-zpravy");
08913 }
08914 }
08915 }
08916 return res;
08917 }
08918
08919
08920 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08921 {
08922 int res;
08923
08924 res = ast_play_and_wait(chan, "vm-you");
08925
08926 if (!res && vms->newmessages) {
08927 res = ast_play_and_wait(chan, "vm-have");
08928 if (!res)
08929 res = say_and_wait(chan, vms->newmessages, chan->language);
08930 if (!res)
08931 res = ast_play_and_wait(chan, "vm-tong");
08932 if (!res)
08933 res = ast_play_and_wait(chan, "vm-INBOX");
08934 if (vms->oldmessages && !res)
08935 res = ast_play_and_wait(chan, "vm-and");
08936 else if (!res)
08937 res = ast_play_and_wait(chan, "vm-messages");
08938 }
08939 if (!res && vms->oldmessages) {
08940 res = ast_play_and_wait(chan, "vm-have");
08941 if (!res)
08942 res = say_and_wait(chan, vms->oldmessages, chan->language);
08943 if (!res)
08944 res = ast_play_and_wait(chan, "vm-tong");
08945 if (!res)
08946 res = ast_play_and_wait(chan, "vm-Old");
08947 if (!res)
08948 res = ast_play_and_wait(chan, "vm-messages");
08949 }
08950 if (!res && !vms->oldmessages && !vms->newmessages) {
08951 res = ast_play_and_wait(chan, "vm-haveno");
08952 if (!res)
08953 res = ast_play_and_wait(chan, "vm-messages");
08954 }
08955 return res;
08956 }
08957
08958
08959 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
08960 {
08961 int res;
08962
08963
08964 res = ast_play_and_wait(chan, "vm-youhave");
08965 if (!res) {
08966 if (vms->newmessages) {
08967 res = say_and_wait(chan, vms->newmessages, chan->language);
08968 if (!res)
08969 res = ast_play_and_wait(chan, "vm-INBOX");
08970 if (vms->oldmessages && !res)
08971 res = ast_play_and_wait(chan, "vm-and");
08972 }
08973 if (!res && vms->oldmessages) {
08974 res = say_and_wait(chan, vms->oldmessages, chan->language);
08975 if (!res)
08976 res = ast_play_and_wait(chan, "vm-Old");
08977 }
08978 if (!res) {
08979 if (!vms->oldmessages && !vms->newmessages) {
08980 res = ast_play_and_wait(chan, "vm-no");
08981 if (!res)
08982 res = ast_play_and_wait(chan, "vm-message");
08983 }
08984 }
08985 }
08986 return res;
08987 }
08988
08989 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
08990 {
08991 char prefile[256];
08992
08993
08994 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08995 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
08996 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08997 if (ast_fileexists(prefile, NULL, NULL) > 0) {
08998 ast_play_and_wait(chan, "vm-tempgreetactive");
08999 }
09000 DISPOSE(prefile, -1);
09001 }
09002
09003
09004 if (0) {
09005 return 0;
09006 } else if (!strncasecmp(chan->language, "cs", 2)) {
09007 return vm_intro_cs(chan, vms);
09008 } else if (!strncasecmp(chan->language, "cz", 2)) {
09009 static int deprecation_warning = 0;
09010 if (deprecation_warning++ % 10 == 0) {
09011 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09012 }
09013 return vm_intro_cs(chan, vms);
09014 } else if (!strncasecmp(chan->language, "de", 2)) {
09015 return vm_intro_de(chan, vms);
09016 } else if (!strncasecmp(chan->language, "es", 2)) {
09017 return vm_intro_es(chan, vms);
09018 } else if (!strncasecmp(chan->language, "fr", 2)) {
09019 return vm_intro_fr(chan, vms);
09020 } else if (!strncasecmp(chan->language, "gr", 2)) {
09021 return vm_intro_gr(chan, vms);
09022 } else if (!strncasecmp(chan->language, "he", 2)) {
09023 return vm_intro_he(chan, vms);
09024 } else if (!strncasecmp(chan->language, "it", 2)) {
09025 return vm_intro_it(chan, vms);
09026 } else if (!strncasecmp(chan->language, "nl", 2)) {
09027 return vm_intro_nl(chan, vms);
09028 } else if (!strncasecmp(chan->language, "no", 2)) {
09029 return vm_intro_no(chan, vms);
09030 } else if (!strncasecmp(chan->language, "pl", 2)) {
09031 return vm_intro_pl(chan, vms);
09032 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09033 return vm_intro_pt_BR(chan, vms);
09034 } else if (!strncasecmp(chan->language, "pt", 2)) {
09035 return vm_intro_pt(chan, vms);
09036 } else if (!strncasecmp(chan->language, "ru", 2)) {
09037 return vm_intro_multilang(chan, vms, "n");
09038 } else if (!strncasecmp(chan->language, "se", 2)) {
09039 return vm_intro_se(chan, vms);
09040 } else if (!strncasecmp(chan->language, "ua", 2)) {
09041 return vm_intro_multilang(chan, vms, "n");
09042 } else if (!strncasecmp(chan->language, "vi", 2)) {
09043 return vm_intro_vi(chan, vms);
09044 } else if (!strncasecmp(chan->language, "zh", 2)) {
09045 return vm_intro_zh(chan, vms);
09046 } else {
09047 return vm_intro_en(chan, vms);
09048 }
09049 }
09050
09051 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09052 {
09053 int res = 0;
09054
09055 while (!res) {
09056 if (vms->starting) {
09057 if (vms->lastmsg > -1) {
09058 if (skipadvanced)
09059 res = ast_play_and_wait(chan, "vm-onefor-full");
09060 else
09061 res = ast_play_and_wait(chan, "vm-onefor");
09062 if (!res)
09063 res = vm_play_folder_name(chan, vms->vmbox);
09064 }
09065 if (!res) {
09066 if (skipadvanced)
09067 res = ast_play_and_wait(chan, "vm-opts-full");
09068 else
09069 res = ast_play_and_wait(chan, "vm-opts");
09070 }
09071 } else {
09072
09073 if (skipadvanced) {
09074 res = ast_play_and_wait(chan, "vm-onefor-full");
09075 if (!res)
09076 res = vm_play_folder_name(chan, vms->vmbox);
09077 res = ast_play_and_wait(chan, "vm-opts-full");
09078 }
09079
09080
09081
09082
09083
09084
09085 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09086 res = ast_play_and_wait(chan, "vm-prev");
09087 }
09088 if (!res && !skipadvanced)
09089 res = ast_play_and_wait(chan, "vm-advopts");
09090 if (!res)
09091 res = ast_play_and_wait(chan, "vm-repeat");
09092
09093
09094
09095
09096
09097
09098 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09099 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09100 res = ast_play_and_wait(chan, "vm-next");
09101 }
09102 if (!res) {
09103 if (!vms->deleted[vms->curmsg])
09104 res = ast_play_and_wait(chan, "vm-delete");
09105 else
09106 res = ast_play_and_wait(chan, "vm-undelete");
09107 if (!res)
09108 res = ast_play_and_wait(chan, "vm-toforward");
09109 if (!res)
09110 res = ast_play_and_wait(chan, "vm-savemessage");
09111 }
09112 }
09113 if (!res) {
09114 res = ast_play_and_wait(chan, "vm-helpexit");
09115 }
09116 if (!res)
09117 res = ast_waitfordigit(chan, 6000);
09118 if (!res) {
09119 vms->repeats++;
09120 if (vms->repeats > 2) {
09121 res = 't';
09122 }
09123 }
09124 }
09125 return res;
09126 }
09127
09128 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09129 {
09130 int res = 0;
09131
09132 while (!res) {
09133 if (vms->lastmsg > -1) {
09134 res = ast_play_and_wait(chan, "vm-listen");
09135 if (!res)
09136 res = vm_play_folder_name(chan, vms->vmbox);
09137 if (!res)
09138 res = ast_play_and_wait(chan, "press");
09139 if (!res)
09140 res = ast_play_and_wait(chan, "digits/1");
09141 }
09142 if (!res)
09143 res = ast_play_and_wait(chan, "vm-opts");
09144 if (!res) {
09145 vms->starting = 0;
09146 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09147 }
09148 }
09149 return res;
09150 }
09151
09152 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09153 {
09154 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09155 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09156 } else {
09157 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09158 }
09159 }
09160
09161
09162 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09163 {
09164 int cmd = 0;
09165 int duration = 0;
09166 int tries = 0;
09167 char newpassword[80] = "";
09168 char newpassword2[80] = "";
09169 char prefile[PATH_MAX] = "";
09170 unsigned char buf[256];
09171 int bytes = 0;
09172
09173 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09174 if (ast_adsi_available(chan)) {
09175 bytes += adsi_logo(buf + bytes);
09176 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09177 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09178 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09179 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09180 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09181 }
09182
09183
09184 if (ast_test_flag(vmu, VM_FORCENAME)) {
09185 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09186 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09187 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09188 if (cmd < 0 || cmd == 't' || cmd == '#')
09189 return cmd;
09190 }
09191 }
09192
09193
09194 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09195 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09196 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09197 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09198 if (cmd < 0 || cmd == 't' || cmd == '#')
09199 return cmd;
09200 }
09201
09202 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09203 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09204 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09205 if (cmd < 0 || cmd == 't' || cmd == '#')
09206 return cmd;
09207 }
09208 }
09209
09210
09211
09212
09213
09214 for (;;) {
09215 newpassword[1] = '\0';
09216 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09217 if (cmd == '#')
09218 newpassword[0] = '\0';
09219 if (cmd < 0 || cmd == 't' || cmd == '#')
09220 return cmd;
09221 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09222 if (cmd < 0 || cmd == 't' || cmd == '#')
09223 return cmd;
09224 cmd = check_password(vmu, newpassword);
09225 if (cmd != 0) {
09226 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09227 cmd = ast_play_and_wait(chan, vm_invalid_password);
09228 } else {
09229 newpassword2[1] = '\0';
09230 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09231 if (cmd == '#')
09232 newpassword2[0] = '\0';
09233 if (cmd < 0 || cmd == 't' || cmd == '#')
09234 return cmd;
09235 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09236 if (cmd < 0 || cmd == 't' || cmd == '#')
09237 return cmd;
09238 if (!strcmp(newpassword, newpassword2))
09239 break;
09240 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09241 cmd = ast_play_and_wait(chan, vm_mismatch);
09242 }
09243 if (++tries == 3)
09244 return -1;
09245 if (cmd != 0) {
09246 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09247 }
09248 }
09249 if (pwdchange & PWDCHANGE_INTERNAL)
09250 vm_change_password(vmu, newpassword);
09251 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09252 vm_change_password_shell(vmu, newpassword);
09253
09254 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09255 cmd = ast_play_and_wait(chan, vm_passchanged);
09256
09257 return cmd;
09258 }
09259
09260 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09261 {
09262 int cmd = 0;
09263 int retries = 0;
09264 int duration = 0;
09265 char newpassword[80] = "";
09266 char newpassword2[80] = "";
09267 char prefile[PATH_MAX] = "";
09268 unsigned char buf[256];
09269 int bytes = 0;
09270
09271 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09272 if (ast_adsi_available(chan)) {
09273 bytes += adsi_logo(buf + bytes);
09274 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09275 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09276 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09277 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09278 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09279 }
09280 while ((cmd >= 0) && (cmd != 't')) {
09281 if (cmd)
09282 retries = 0;
09283 switch (cmd) {
09284 case '1':
09285 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09286 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09287 break;
09288 case '2':
09289 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09290 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09291 break;
09292 case '3':
09293 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09294 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09295 break;
09296 case '4':
09297 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09298 break;
09299 case '5':
09300 if (vmu->password[0] == '-') {
09301 cmd = ast_play_and_wait(chan, "vm-no");
09302 break;
09303 }
09304 newpassword[1] = '\0';
09305 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09306 if (cmd == '#')
09307 newpassword[0] = '\0';
09308 else {
09309 if (cmd < 0)
09310 break;
09311 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09312 break;
09313 }
09314 }
09315 cmd = check_password(vmu, newpassword);
09316 if (cmd != 0) {
09317 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09318 cmd = ast_play_and_wait(chan, vm_invalid_password);
09319 if (!cmd) {
09320 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09321 }
09322 break;
09323 }
09324 newpassword2[1] = '\0';
09325 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09326 if (cmd == '#')
09327 newpassword2[0] = '\0';
09328 else {
09329 if (cmd < 0)
09330 break;
09331
09332 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09333 break;
09334 }
09335 }
09336 if (strcmp(newpassword, newpassword2)) {
09337 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09338 cmd = ast_play_and_wait(chan, vm_mismatch);
09339 if (!cmd) {
09340 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09341 }
09342 break;
09343 }
09344
09345 if (pwdchange & PWDCHANGE_INTERNAL) {
09346 vm_change_password(vmu, newpassword);
09347 }
09348 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09349 vm_change_password_shell(vmu, newpassword);
09350 }
09351
09352 ast_debug(1, "User %s set password to %s of length %d\n",
09353 vms->username, newpassword, (int) strlen(newpassword));
09354 cmd = ast_play_and_wait(chan, vm_passchanged);
09355 break;
09356 case '*':
09357 cmd = 't';
09358 break;
09359 default:
09360 cmd = 0;
09361 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09362 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09363 if (ast_fileexists(prefile, NULL, NULL)) {
09364 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09365 }
09366 DISPOSE(prefile, -1);
09367 if (!cmd) {
09368 cmd = ast_play_and_wait(chan, "vm-options");
09369 }
09370 if (!cmd) {
09371 cmd = ast_waitfordigit(chan, 6000);
09372 }
09373 if (!cmd) {
09374 retries++;
09375 }
09376 if (retries > 3) {
09377 cmd = 't';
09378 }
09379 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09380 }
09381 }
09382 if (cmd == 't')
09383 cmd = 0;
09384 return cmd;
09385 }
09386
09387
09388
09389
09390
09391
09392
09393
09394
09395
09396
09397
09398
09399
09400
09401
09402
09403 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09404 {
09405 int cmd = 0;
09406 int retries = 0;
09407 int duration = 0;
09408 char prefile[PATH_MAX] = "";
09409 unsigned char buf[256];
09410 int bytes = 0;
09411
09412 if (ast_adsi_available(chan)) {
09413 bytes += adsi_logo(buf + bytes);
09414 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09415 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09416 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09417 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09418 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09419 }
09420
09421 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09422 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09423 while ((cmd >= 0) && (cmd != 't')) {
09424 if (cmd)
09425 retries = 0;
09426 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09427 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09428 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09429 cmd = 't';
09430 } else {
09431 switch (cmd) {
09432 case '1':
09433 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09434 break;
09435 case '2':
09436 DELETE(prefile, -1, prefile, vmu);
09437 ast_play_and_wait(chan, "vm-tempremoved");
09438 cmd = 't';
09439 break;
09440 case '*':
09441 cmd = 't';
09442 break;
09443 default:
09444 cmd = ast_play_and_wait(chan,
09445 ast_fileexists(prefile, NULL, NULL) > 0 ?
09446 "vm-tempgreeting2" : "vm-tempgreeting");
09447 if (!cmd) {
09448 cmd = ast_waitfordigit(chan, 6000);
09449 }
09450 if (!cmd) {
09451 retries++;
09452 }
09453 if (retries > 3) {
09454 cmd = 't';
09455 }
09456 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09457 }
09458 }
09459 DISPOSE(prefile, -1);
09460 }
09461 if (cmd == 't')
09462 cmd = 0;
09463 return cmd;
09464 }
09465
09466
09467
09468
09469
09470
09471
09472
09473
09474 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09475 {
09476 int cmd = 0;
09477
09478 if (vms->lastmsg > -1) {
09479 cmd = play_message(chan, vmu, vms);
09480 } else {
09481 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09482 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09483 if (!cmd) {
09484 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09485 cmd = ast_play_and_wait(chan, vms->fn);
09486 }
09487 if (!cmd)
09488 cmd = ast_play_and_wait(chan, "vm-messages");
09489 } else {
09490 if (!cmd)
09491 cmd = ast_play_and_wait(chan, "vm-messages");
09492 if (!cmd) {
09493 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09494 cmd = ast_play_and_wait(chan, vms->fn);
09495 }
09496 }
09497 }
09498 return cmd;
09499 }
09500
09501
09502 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09503 {
09504 int cmd = 0;
09505
09506 if (vms->lastmsg > -1) {
09507 cmd = play_message(chan, vmu, vms);
09508 } else {
09509 if (!strcasecmp(vms->fn, "INBOX")) {
09510 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09511 } else {
09512 cmd = ast_play_and_wait(chan, "vm-nomessages");
09513 }
09514 }
09515 return cmd;
09516 }
09517
09518
09519
09520
09521
09522
09523
09524
09525
09526 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09527 {
09528 int cmd = 0;
09529
09530 if (vms->lastmsg > -1) {
09531 cmd = play_message(chan, vmu, vms);
09532 } else {
09533 cmd = ast_play_and_wait(chan, "vm-youhave");
09534 if (!cmd)
09535 cmd = ast_play_and_wait(chan, "vm-no");
09536 if (!cmd) {
09537 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09538 cmd = ast_play_and_wait(chan, vms->fn);
09539 }
09540 if (!cmd)
09541 cmd = ast_play_and_wait(chan, "vm-messages");
09542 }
09543 return cmd;
09544 }
09545
09546
09547
09548
09549
09550
09551
09552
09553
09554 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09555 {
09556 int cmd;
09557
09558 if (vms->lastmsg > -1) {
09559 cmd = play_message(chan, vmu, vms);
09560 } else {
09561 cmd = ast_play_and_wait(chan, "vm-no");
09562 if (!cmd)
09563 cmd = ast_play_and_wait(chan, "vm-message");
09564 if (!cmd) {
09565 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09566 cmd = ast_play_and_wait(chan, vms->fn);
09567 }
09568 }
09569 return cmd;
09570 }
09571
09572
09573
09574
09575
09576
09577
09578
09579
09580 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09581 {
09582 int cmd;
09583
09584 if (vms->lastmsg > -1) {
09585 cmd = play_message(chan, vmu, vms);
09586 } else {
09587 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09588 if (!cmd)
09589 cmd = ast_play_and_wait(chan, "vm-messages");
09590 if (!cmd) {
09591 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09592 cmd = ast_play_and_wait(chan, vms->fn);
09593 }
09594 }
09595 return cmd;
09596 }
09597
09598
09599
09600
09601
09602
09603
09604
09605
09606 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09607 {
09608 int cmd;
09609
09610 if (vms->lastmsg > -1) {
09611 cmd = play_message(chan, vmu, vms);
09612 } else {
09613 cmd = ast_play_and_wait(chan, "vm-no");
09614 if (!cmd) {
09615 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09616 cmd = ast_play_and_wait(chan, vms->fn);
09617 }
09618 if (!cmd)
09619 cmd = ast_play_and_wait(chan, "vm-messages");
09620 }
09621 return cmd;
09622 }
09623
09624
09625
09626
09627
09628
09629
09630
09631
09632 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09633 {
09634 int cmd;
09635
09636 if (vms->lastmsg > -1) {
09637 cmd = play_message(chan, vmu, vms);
09638 } else {
09639 cmd = ast_play_and_wait(chan, "vm-you");
09640 if (!cmd)
09641 cmd = ast_play_and_wait(chan, "vm-haveno");
09642 if (!cmd)
09643 cmd = ast_play_and_wait(chan, "vm-messages");
09644 if (!cmd) {
09645 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09646 cmd = ast_play_and_wait(chan, vms->fn);
09647 }
09648 }
09649 return cmd;
09650 }
09651
09652
09653
09654
09655
09656
09657
09658
09659
09660 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09661 {
09662 int cmd = 0;
09663
09664 if (vms->lastmsg > -1) {
09665 cmd = play_message(chan, vmu, vms);
09666 } else {
09667 cmd = ast_play_and_wait(chan, "vm-no");
09668 if (!cmd) {
09669 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09670 cmd = ast_play_and_wait(chan, vms->fn);
09671 }
09672 }
09673 return cmd;
09674 }
09675
09676
09677
09678
09679
09680
09681
09682
09683
09684
09685
09686
09687 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09688 {
09689 if (!strncasecmp(chan->language, "es", 2)) {
09690 return vm_browse_messages_es(chan, vms, vmu);
09691 } else if (!strncasecmp(chan->language, "gr", 2)) {
09692 return vm_browse_messages_gr(chan, vms, vmu);
09693 } else if (!strncasecmp(chan->language, "he", 2)) {
09694 return vm_browse_messages_he(chan, vms, vmu);
09695 } else if (!strncasecmp(chan->language, "it", 2)) {
09696 return vm_browse_messages_it(chan, vms, vmu);
09697 } else if (!strncasecmp(chan->language, "pt", 2)) {
09698 return vm_browse_messages_pt(chan, vms, vmu);
09699 } else if (!strncasecmp(chan->language, "vi", 2)) {
09700 return vm_browse_messages_vi(chan, vms, vmu);
09701 } else if (!strncasecmp(chan->language, "zh", 2)) {
09702 return vm_browse_messages_zh(chan, vms, vmu);
09703 } else {
09704 return vm_browse_messages_en(chan, vms, vmu);
09705 }
09706 }
09707
09708 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09709 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09710 int skipuser, int max_logins, int silent)
09711 {
09712 int useadsi = 0, valid = 0, logretries = 0;
09713 char password[AST_MAX_EXTENSION]="", *passptr;
09714 struct ast_vm_user vmus, *vmu = NULL;
09715
09716
09717 adsi_begin(chan, &useadsi);
09718 if (!skipuser && useadsi)
09719 adsi_login(chan);
09720 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09721 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09722 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09723 return -1;
09724 }
09725
09726
09727
09728 while (!valid && (logretries < max_logins)) {
09729
09730 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09731 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09732 return -1;
09733 }
09734 if (ast_strlen_zero(mailbox)) {
09735 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09736 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09737 } else {
09738 ast_verb(3, "Username not entered\n");
09739 return -1;
09740 }
09741 } else if (mailbox[0] == '*') {
09742
09743 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09744 if (ast_exists_extension(chan, chan->context, "a", 1,
09745 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09746 return -1;
09747 }
09748 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09749 mailbox[0] = '\0';
09750 }
09751
09752 if (useadsi)
09753 adsi_password(chan);
09754
09755 if (!ast_strlen_zero(prefix)) {
09756 char fullusername[80] = "";
09757 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09758 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09759 ast_copy_string(mailbox, fullusername, mailbox_size);
09760 }
09761
09762 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09763 vmu = find_user(&vmus, context, mailbox);
09764 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09765
09766 password[0] = '\0';
09767 } else {
09768 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09769 if (ast_streamfile(chan, vm_password, chan->language)) {
09770 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09771 return -1;
09772 }
09773 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09774 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09775 return -1;
09776 } else if (password[0] == '*') {
09777
09778 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09779 if (ast_exists_extension(chan, chan->context, "a", 1,
09780 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09781 mailbox[0] = '*';
09782 return -1;
09783 }
09784 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09785 mailbox[0] = '\0';
09786
09787 vmu = NULL;
09788 }
09789 }
09790
09791 if (vmu) {
09792 passptr = vmu->password;
09793 if (passptr[0] == '-') passptr++;
09794 }
09795 if (vmu && !strcmp(passptr, password))
09796 valid++;
09797 else {
09798 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09799 if (!ast_strlen_zero(prefix))
09800 mailbox[0] = '\0';
09801 }
09802 logretries++;
09803 if (!valid) {
09804 if (skipuser || logretries >= max_logins) {
09805 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09806 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09807 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09808 return -1;
09809 }
09810 } else {
09811 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09812 if (useadsi)
09813 adsi_login(chan);
09814 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09815 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09816 return -1;
09817 }
09818 }
09819 if (ast_waitstream(chan, ""))
09820 return -1;
09821 }
09822 }
09823 if (!valid && (logretries >= max_logins)) {
09824 ast_stopstream(chan);
09825 ast_play_and_wait(chan, "vm-goodbye");
09826 return -1;
09827 }
09828 if (vmu && !skipuser) {
09829 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09830 }
09831 return 0;
09832 }
09833
09834 static int vm_execmain(struct ast_channel *chan, const char *data)
09835 {
09836
09837
09838
09839 int res = -1;
09840 int cmd = 0;
09841 int valid = 0;
09842 char prefixstr[80] ="";
09843 char ext_context[256]="";
09844 int box;
09845 int useadsi = 0;
09846 int skipuser = 0;
09847 struct vm_state vms;
09848 struct ast_vm_user *vmu = NULL, vmus;
09849 char *context = NULL;
09850 int silentexit = 0;
09851 struct ast_flags flags = { 0 };
09852 signed char record_gain = 0;
09853 int play_auto = 0;
09854 int play_folder = 0;
09855 int in_urgent = 0;
09856 #ifdef IMAP_STORAGE
09857 int deleted = 0;
09858 #endif
09859
09860
09861 memset(&vms, 0, sizeof(vms));
09862
09863 vms.lastmsg = -1;
09864
09865 memset(&vmus, 0, sizeof(vmus));
09866
09867 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09868 if (chan->_state != AST_STATE_UP) {
09869 ast_debug(1, "Before ast_answer\n");
09870 ast_answer(chan);
09871 }
09872
09873 if (!ast_strlen_zero(data)) {
09874 char *opts[OPT_ARG_ARRAY_SIZE];
09875 char *parse;
09876 AST_DECLARE_APP_ARGS(args,
09877 AST_APP_ARG(argv0);
09878 AST_APP_ARG(argv1);
09879 );
09880
09881 parse = ast_strdupa(data);
09882
09883 AST_STANDARD_APP_ARGS(args, parse);
09884
09885 if (args.argc == 2) {
09886 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09887 return -1;
09888 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09889 int gain;
09890 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09891 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09892 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09893 return -1;
09894 } else {
09895 record_gain = (signed char) gain;
09896 }
09897 } else {
09898 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09899 }
09900 }
09901 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09902 play_auto = 1;
09903 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09904
09905 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09906 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09907 play_folder = -1;
09908 }
09909 } else {
09910 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09911 }
09912 } else {
09913 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09914 }
09915 if (play_folder > 9 || play_folder < 0) {
09916 ast_log(AST_LOG_WARNING,
09917 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09918 opts[OPT_ARG_PLAYFOLDER]);
09919 play_folder = 0;
09920 }
09921 }
09922 } else {
09923
09924 while (*(args.argv0)) {
09925 if (*(args.argv0) == 's')
09926 ast_set_flag(&flags, OPT_SILENT);
09927 else if (*(args.argv0) == 'p')
09928 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09929 else
09930 break;
09931 (args.argv0)++;
09932 }
09933
09934 }
09935
09936 valid = ast_test_flag(&flags, OPT_SILENT);
09937
09938 if ((context = strchr(args.argv0, '@')))
09939 *context++ = '\0';
09940
09941 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09942 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09943 else
09944 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09945
09946 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09947 skipuser++;
09948 else
09949 valid = 0;
09950 }
09951
09952 if (!valid)
09953 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09954
09955 ast_debug(1, "After vm_authenticate\n");
09956
09957 if (vms.username[0] == '*') {
09958 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09959
09960
09961 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
09962 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
09963 res = 0;
09964 goto out;
09965 }
09966 }
09967
09968 if (!res) {
09969 valid = 1;
09970 if (!skipuser)
09971 vmu = &vmus;
09972 } else {
09973 res = 0;
09974 }
09975
09976
09977 adsi_begin(chan, &useadsi);
09978
09979 ast_test_suite_assert(valid);
09980 if (!valid) {
09981 goto out;
09982 }
09983 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
09984
09985 #ifdef IMAP_STORAGE
09986 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
09987 pthread_setspecific(ts_vmstate.key, &vms);
09988
09989 vms.interactive = 1;
09990 vms.updated = 1;
09991 if (vmu)
09992 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
09993 vmstate_insert(&vms);
09994 init_vm_state(&vms);
09995 #endif
09996
09997 if (!(vms.deleted = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
09998 ast_log(AST_LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
09999 cmd = ast_play_and_wait(chan, "an-error-has-occured");
10000 return -1;
10001 }
10002 if (!(vms.heard = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
10003 ast_log(AST_LOG_ERROR, "Could not allocate memory for heard message storage!\n");
10004 cmd = ast_play_and_wait(chan, "an-error-has-occured");
10005 return -1;
10006 }
10007
10008
10009 if (!ast_strlen_zero(vmu->language))
10010 ast_string_field_set(chan, language, vmu->language);
10011
10012
10013 ast_debug(1, "Before open_mailbox\n");
10014 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10015 if (res < 0)
10016 goto out;
10017 vms.oldmessages = vms.lastmsg + 1;
10018 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10019
10020 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10021 if (res < 0)
10022 goto out;
10023 vms.newmessages = vms.lastmsg + 1;
10024 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10025
10026 in_urgent = 1;
10027 res = open_mailbox(&vms, vmu, 11);
10028 if (res < 0)
10029 goto out;
10030 vms.urgentmessages = vms.lastmsg + 1;
10031 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10032
10033
10034 if (play_auto) {
10035 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10036 if (vms.urgentmessages) {
10037 in_urgent = 1;
10038 res = open_mailbox(&vms, vmu, 11);
10039 } else {
10040 in_urgent = 0;
10041 res = open_mailbox(&vms, vmu, play_folder);
10042 }
10043 if (res < 0)
10044 goto out;
10045
10046
10047 if (vms.lastmsg == -1) {
10048 in_urgent = 0;
10049 cmd = vm_browse_messages(chan, &vms, vmu);
10050 res = 0;
10051 goto out;
10052 }
10053 } else {
10054 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10055
10056 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10057 in_urgent = 0;
10058 play_folder = 1;
10059 if (res < 0)
10060 goto out;
10061 } else if (!vms.urgentmessages && vms.newmessages) {
10062
10063 in_urgent = 0;
10064 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10065 if (res < 0)
10066 goto out;
10067 }
10068 }
10069
10070 if (useadsi)
10071 adsi_status(chan, &vms);
10072 res = 0;
10073
10074
10075 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10076 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10077 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10078 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10079 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10080 if ((cmd == 't') || (cmd == '#')) {
10081
10082 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10083 res = 0;
10084 goto out;
10085 } else if (cmd < 0) {
10086
10087 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10088 res = -1;
10089 goto out;
10090 }
10091 }
10092 #ifdef IMAP_STORAGE
10093 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10094 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10095 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10096 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10097 }
10098 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10099 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10100 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10101 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10102 }
10103 #endif
10104
10105 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10106 if (play_auto) {
10107 cmd = '1';
10108 } else {
10109 cmd = vm_intro(chan, vmu, &vms);
10110 }
10111 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10112
10113 vms.repeats = 0;
10114 vms.starting = 1;
10115 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10116
10117 switch (cmd) {
10118 case '1':
10119 vms.curmsg = 0;
10120
10121 case '5':
10122 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10123 cmd = vm_browse_messages(chan, &vms, vmu);
10124 break;
10125 case '2':
10126 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10127 if (useadsi)
10128 adsi_folders(chan, 0, "Change to folder...");
10129
10130 cmd = get_folder2(chan, "vm-changeto", 0);
10131 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10132 if (cmd == '#') {
10133 cmd = 0;
10134 } else if (cmd > 0) {
10135 cmd = cmd - '0';
10136 res = close_mailbox(&vms, vmu);
10137 if (res == ERROR_LOCK_PATH)
10138 goto out;
10139
10140 if (cmd != 11) in_urgent = 0;
10141 res = open_mailbox(&vms, vmu, cmd);
10142 if (res < 0)
10143 goto out;
10144 play_folder = cmd;
10145 cmd = 0;
10146 }
10147 if (useadsi)
10148 adsi_status2(chan, &vms);
10149
10150 if (!cmd) {
10151 cmd = vm_play_folder_name(chan, vms.vmbox);
10152 }
10153
10154 vms.starting = 1;
10155 break;
10156 case '3':
10157 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10158 cmd = 0;
10159 vms.repeats = 0;
10160 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10161 switch (cmd) {
10162 case '1':
10163 if (vms.lastmsg > -1 && !vms.starting) {
10164 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10165 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10166 res = cmd;
10167 goto out;
10168 }
10169 } else {
10170 cmd = ast_play_and_wait(chan, "vm-sorry");
10171 }
10172 cmd = 't';
10173 break;
10174 case '2':
10175 if (!vms.starting)
10176 ast_verb(3, "Callback Requested\n");
10177 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10178 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10179 if (cmd == 9) {
10180 silentexit = 1;
10181 goto out;
10182 } else if (cmd == ERROR_LOCK_PATH) {
10183 res = cmd;
10184 goto out;
10185 }
10186 } else {
10187 cmd = ast_play_and_wait(chan, "vm-sorry");
10188 }
10189 cmd = 't';
10190 break;
10191 case '3':
10192 if (vms.lastmsg > -1 && !vms.starting) {
10193 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10194 if (cmd == ERROR_LOCK_PATH) {
10195 res = cmd;
10196 goto out;
10197 }
10198 } else {
10199 cmd = ast_play_and_wait(chan, "vm-sorry");
10200 }
10201 cmd = 't';
10202 break;
10203 case '4':
10204 if (!ast_strlen_zero(vmu->dialout)) {
10205 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10206 if (cmd == 9) {
10207 silentexit = 1;
10208 goto out;
10209 }
10210 } else {
10211 cmd = ast_play_and_wait(chan, "vm-sorry");
10212 }
10213 cmd = 't';
10214 break;
10215
10216 case '5':
10217 if (ast_test_flag(vmu, VM_SVMAIL)) {
10218 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10219 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10220 res = cmd;
10221 goto out;
10222 }
10223 } else {
10224 cmd = ast_play_and_wait(chan, "vm-sorry");
10225 }
10226 cmd = 't';
10227 break;
10228
10229 case '*':
10230 cmd = 't';
10231 break;
10232
10233 default:
10234 cmd = 0;
10235 if (!vms.starting) {
10236 cmd = ast_play_and_wait(chan, "vm-toreply");
10237 }
10238 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10239 cmd = ast_play_and_wait(chan, "vm-tocallback");
10240 }
10241 if (!cmd && !vms.starting) {
10242 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10243 }
10244 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10245 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10246 }
10247 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10248 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10249 }
10250 if (!cmd) {
10251 cmd = ast_play_and_wait(chan, "vm-starmain");
10252 }
10253 if (!cmd) {
10254 cmd = ast_waitfordigit(chan, 6000);
10255 }
10256 if (!cmd) {
10257 vms.repeats++;
10258 }
10259 if (vms.repeats > 3) {
10260 cmd = 't';
10261 }
10262 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10263 }
10264 }
10265 if (cmd == 't') {
10266 cmd = 0;
10267 vms.repeats = 0;
10268 }
10269 break;
10270 case '4':
10271 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10272 if (vms.curmsg > 0) {
10273 vms.curmsg--;
10274 cmd = play_message(chan, vmu, &vms);
10275 } else {
10276
10277
10278
10279
10280 if (in_urgent == 0 && vms.urgentmessages > 0) {
10281
10282 in_urgent = 1;
10283 res = close_mailbox(&vms, vmu);
10284 if (res == ERROR_LOCK_PATH)
10285 goto out;
10286 res = open_mailbox(&vms, vmu, 11);
10287 if (res < 0)
10288 goto out;
10289 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10290 vms.curmsg = vms.lastmsg;
10291 if (vms.lastmsg < 0) {
10292 cmd = ast_play_and_wait(chan, "vm-nomore");
10293 }
10294 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10295 vms.curmsg = vms.lastmsg;
10296 cmd = play_message(chan, vmu, &vms);
10297 } else {
10298 cmd = ast_play_and_wait(chan, "vm-nomore");
10299 }
10300 }
10301 break;
10302 case '6':
10303 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10304 if (vms.curmsg < vms.lastmsg) {
10305 vms.curmsg++;
10306 cmd = play_message(chan, vmu, &vms);
10307 } else {
10308 if (in_urgent && vms.newmessages > 0) {
10309
10310
10311
10312
10313 in_urgent = 0;
10314 res = close_mailbox(&vms, vmu);
10315 if (res == ERROR_LOCK_PATH)
10316 goto out;
10317 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10318 if (res < 0)
10319 goto out;
10320 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10321 vms.curmsg = -1;
10322 if (vms.lastmsg < 0) {
10323 cmd = ast_play_and_wait(chan, "vm-nomore");
10324 }
10325 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10326 vms.curmsg = 0;
10327 cmd = play_message(chan, vmu, &vms);
10328 } else {
10329 cmd = ast_play_and_wait(chan, "vm-nomore");
10330 }
10331 }
10332 break;
10333 case '7':
10334 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10335 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10336 if (useadsi)
10337 adsi_delete(chan, &vms);
10338 if (vms.deleted[vms.curmsg]) {
10339 if (play_folder == 0) {
10340 if (in_urgent) {
10341 vms.urgentmessages--;
10342 } else {
10343 vms.newmessages--;
10344 }
10345 }
10346 else if (play_folder == 1)
10347 vms.oldmessages--;
10348 cmd = ast_play_and_wait(chan, "vm-deleted");
10349 } else {
10350 if (play_folder == 0) {
10351 if (in_urgent) {
10352 vms.urgentmessages++;
10353 } else {
10354 vms.newmessages++;
10355 }
10356 }
10357 else if (play_folder == 1)
10358 vms.oldmessages++;
10359 cmd = ast_play_and_wait(chan, "vm-undeleted");
10360 }
10361 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10362 if (vms.curmsg < vms.lastmsg) {
10363 vms.curmsg++;
10364 cmd = play_message(chan, vmu, &vms);
10365 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10366 vms.curmsg = 0;
10367 cmd = play_message(chan, vmu, &vms);
10368 } else {
10369
10370
10371
10372
10373 if (in_urgent == 1) {
10374
10375 in_urgent = 0;
10376 res = close_mailbox(&vms, vmu);
10377 if (res == ERROR_LOCK_PATH)
10378 goto out;
10379 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10380 if (res < 0)
10381 goto out;
10382 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10383 vms.curmsg = -1;
10384 if (vms.lastmsg < 0) {
10385 cmd = ast_play_and_wait(chan, "vm-nomore");
10386 }
10387 } else {
10388 cmd = ast_play_and_wait(chan, "vm-nomore");
10389 }
10390 }
10391 }
10392 } else
10393 cmd = 0;
10394 #ifdef IMAP_STORAGE
10395 deleted = 1;
10396 #endif
10397 break;
10398
10399 case '8':
10400 if (vms.lastmsg > -1) {
10401 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10402 if (cmd == ERROR_LOCK_PATH) {
10403 res = cmd;
10404 goto out;
10405 }
10406 } else {
10407
10408
10409
10410
10411 if (in_urgent == 1 && vms.newmessages > 0) {
10412
10413 in_urgent = 0;
10414 res = close_mailbox(&vms, vmu);
10415 if (res == ERROR_LOCK_PATH)
10416 goto out;
10417 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10418 if (res < 0)
10419 goto out;
10420 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10421 vms.curmsg = -1;
10422 if (vms.lastmsg < 0) {
10423 cmd = ast_play_and_wait(chan, "vm-nomore");
10424 }
10425 } else {
10426 cmd = ast_play_and_wait(chan, "vm-nomore");
10427 }
10428 }
10429 break;
10430 case '9':
10431 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10432 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10433
10434 cmd = 0;
10435 break;
10436 }
10437 if (useadsi)
10438 adsi_folders(chan, 1, "Save to folder...");
10439 cmd = get_folder2(chan, "vm-savefolder", 1);
10440 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10441 box = 0;
10442 if (cmd == '#') {
10443 cmd = 0;
10444 break;
10445 } else if (cmd > 0) {
10446 box = cmd = cmd - '0';
10447 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10448 if (cmd == ERROR_LOCK_PATH) {
10449 res = cmd;
10450 goto out;
10451 #ifndef IMAP_STORAGE
10452 } else if (!cmd) {
10453 vms.deleted[vms.curmsg] = 1;
10454 #endif
10455 } else {
10456 vms.deleted[vms.curmsg] = 0;
10457 vms.heard[vms.curmsg] = 0;
10458 }
10459 }
10460 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10461 if (useadsi)
10462 adsi_message(chan, &vms);
10463 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10464 if (!cmd) {
10465 cmd = ast_play_and_wait(chan, "vm-message");
10466 if (!cmd)
10467 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10468 if (!cmd)
10469 cmd = ast_play_and_wait(chan, "vm-savedto");
10470 if (!cmd)
10471 cmd = vm_play_folder_name(chan, vms.fn);
10472 } else {
10473 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10474 }
10475 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10476 if (vms.curmsg < vms.lastmsg) {
10477 vms.curmsg++;
10478 cmd = play_message(chan, vmu, &vms);
10479 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10480 vms.curmsg = 0;
10481 cmd = play_message(chan, vmu, &vms);
10482 } else {
10483
10484
10485
10486
10487 if (in_urgent == 1 && vms.newmessages > 0) {
10488
10489 in_urgent = 0;
10490 res = close_mailbox(&vms, vmu);
10491 if (res == ERROR_LOCK_PATH)
10492 goto out;
10493 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10494 if (res < 0)
10495 goto out;
10496 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10497 vms.curmsg = -1;
10498 if (vms.lastmsg < 0) {
10499 cmd = ast_play_and_wait(chan, "vm-nomore");
10500 }
10501 } else {
10502 cmd = ast_play_and_wait(chan, "vm-nomore");
10503 }
10504 }
10505 }
10506 break;
10507 case '*':
10508 if (!vms.starting) {
10509 cmd = ast_play_and_wait(chan, "vm-onefor");
10510 if (!strncasecmp(chan->language, "he", 2)) {
10511 cmd = ast_play_and_wait(chan, "vm-for");
10512 }
10513 if (!cmd)
10514 cmd = vm_play_folder_name(chan, vms.vmbox);
10515 if (!cmd)
10516 cmd = ast_play_and_wait(chan, "vm-opts");
10517 if (!cmd)
10518 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10519 } else
10520 cmd = 0;
10521 break;
10522 case '0':
10523 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10524 if (useadsi)
10525 adsi_status(chan, &vms);
10526 break;
10527 default:
10528 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10529 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10530 break;
10531 }
10532 }
10533 if ((cmd == 't') || (cmd == '#')) {
10534
10535 res = 0;
10536 } else {
10537
10538 res = -1;
10539 }
10540
10541 out:
10542 if (res > -1) {
10543 ast_stopstream(chan);
10544 adsi_goodbye(chan);
10545 if (valid && res != OPERATOR_EXIT) {
10546 if (silentexit)
10547 res = ast_play_and_wait(chan, "vm-dialout");
10548 else
10549 res = ast_play_and_wait(chan, "vm-goodbye");
10550 }
10551 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10552 res = 0;
10553 }
10554 if (useadsi)
10555 ast_adsi_unload_session(chan);
10556 }
10557 if (vmu)
10558 close_mailbox(&vms, vmu);
10559 if (valid) {
10560 int new = 0, old = 0, urgent = 0;
10561 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10562 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10563
10564 run_externnotify(vmu->context, vmu->mailbox, NULL);
10565 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10566 queue_mwi_event(ext_context, urgent, new, old);
10567 }
10568 #ifdef IMAP_STORAGE
10569
10570 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10571 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10572 ast_mutex_lock(&vms.lock);
10573 #ifdef HAVE_IMAP_TK2006
10574 if (LEVELUIDPLUS (vms.mailstream)) {
10575 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10576 } else
10577 #endif
10578 mail_expunge(vms.mailstream);
10579 ast_mutex_unlock(&vms.lock);
10580 }
10581
10582
10583 if (vmu) {
10584 vmstate_delete(&vms);
10585 }
10586 #endif
10587 if (vmu)
10588 free_user(vmu);
10589 if (vms.deleted)
10590 ast_free(vms.deleted);
10591 if (vms.heard)
10592 ast_free(vms.heard);
10593
10594 #ifdef IMAP_STORAGE
10595 pthread_setspecific(ts_vmstate.key, NULL);
10596 #endif
10597 return res;
10598 }
10599
10600 static int vm_exec(struct ast_channel *chan, const char *data)
10601 {
10602 int res = 0;
10603 char *tmp;
10604 struct leave_vm_options leave_options;
10605 struct ast_flags flags = { 0 };
10606 char *opts[OPT_ARG_ARRAY_SIZE];
10607 AST_DECLARE_APP_ARGS(args,
10608 AST_APP_ARG(argv0);
10609 AST_APP_ARG(argv1);
10610 );
10611
10612 memset(&leave_options, 0, sizeof(leave_options));
10613
10614 if (chan->_state != AST_STATE_UP)
10615 ast_answer(chan);
10616
10617 if (!ast_strlen_zero(data)) {
10618 tmp = ast_strdupa(data);
10619 AST_STANDARD_APP_ARGS(args, tmp);
10620 if (args.argc == 2) {
10621 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10622 return -1;
10623 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10624 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10625 int gain;
10626
10627 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10628 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10629 return -1;
10630 } else {
10631 leave_options.record_gain = (signed char) gain;
10632 }
10633 }
10634 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10635 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10636 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10637 }
10638 }
10639 } else {
10640 char temp[256];
10641 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10642 if (res < 0)
10643 return res;
10644 if (ast_strlen_zero(temp))
10645 return 0;
10646 args.argv0 = ast_strdupa(temp);
10647 }
10648
10649 res = leave_voicemail(chan, args.argv0, &leave_options);
10650 if (res == 't') {
10651 ast_play_and_wait(chan, "vm-goodbye");
10652 res = 0;
10653 }
10654
10655 if (res == OPERATOR_EXIT) {
10656 res = 0;
10657 }
10658
10659 if (res == ERROR_LOCK_PATH) {
10660 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10661 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10662 res = 0;
10663 }
10664
10665 return res;
10666 }
10667
10668 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10669 {
10670 struct ast_vm_user *vmu;
10671
10672 if (!ast_strlen_zero(box) && box[0] == '*') {
10673 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10674 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10675 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10676 "\n\tand will be ignored.\n", box, context);
10677 return NULL;
10678 }
10679
10680 AST_LIST_TRAVERSE(&users, vmu, list) {
10681 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10682 if (strcasecmp(vmu->context, context)) {
10683 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10684 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10685 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10686 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10687 }
10688 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10689 return NULL;
10690 }
10691 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10692 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10693 return NULL;
10694 }
10695 }
10696
10697 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10698 return NULL;
10699
10700 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10701 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10702
10703 AST_LIST_INSERT_TAIL(&users, vmu, list);
10704
10705 return vmu;
10706 }
10707
10708 static int append_mailbox(const char *context, const char *box, const char *data)
10709 {
10710
10711 char *tmp;
10712 char *stringp;
10713 char *s;
10714 struct ast_vm_user *vmu;
10715 char *mailbox_full;
10716 int new = 0, old = 0, urgent = 0;
10717 char secretfn[PATH_MAX] = "";
10718
10719 tmp = ast_strdupa(data);
10720
10721 if (!(vmu = find_or_create(context, box)))
10722 return -1;
10723
10724 populate_defaults(vmu);
10725
10726 stringp = tmp;
10727 if ((s = strsep(&stringp, ","))) {
10728 if (!ast_strlen_zero(s) && s[0] == '*') {
10729 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10730 "\n\tmust be reset in voicemail.conf.\n", box);
10731 }
10732
10733 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10734 }
10735 if (stringp && (s = strsep(&stringp, ","))) {
10736 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10737 }
10738 if (stringp && (s = strsep(&stringp, ","))) {
10739 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10740 }
10741 if (stringp && (s = strsep(&stringp, ","))) {
10742 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10743 }
10744 if (stringp && (s = strsep(&stringp, ","))) {
10745 apply_options(vmu, s);
10746 }
10747
10748 switch (vmu->passwordlocation) {
10749 case OPT_PWLOC_SPOOLDIR:
10750 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10751 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10752 }
10753
10754 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10755 strcpy(mailbox_full, box);
10756 strcat(mailbox_full, "@");
10757 strcat(mailbox_full, context);
10758
10759 inboxcount2(mailbox_full, &urgent, &new, &old);
10760 queue_mwi_event(mailbox_full, urgent, new, old);
10761
10762 return 0;
10763 }
10764
10765 AST_TEST_DEFINE(test_voicemail_vmuser)
10766 {
10767 int res = 0;
10768 struct ast_vm_user *vmu;
10769
10770 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10771 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10772 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10773 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10774 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10775 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10776 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10777 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10778 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10779 #ifdef IMAP_STORAGE
10780 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10781 "imapfolder=INBOX|imapvmshareid=6000";
10782 #endif
10783
10784 switch (cmd) {
10785 case TEST_INIT:
10786 info->name = "vmuser";
10787 info->category = "/apps/app_voicemail/";
10788 info->summary = "Vmuser unit test";
10789 info->description =
10790 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10791 return AST_TEST_NOT_RUN;
10792 case TEST_EXECUTE:
10793 break;
10794 }
10795
10796 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10797 return AST_TEST_NOT_RUN;
10798 }
10799 ast_set_flag(vmu, VM_ALLOCED);
10800 populate_defaults(vmu);
10801
10802 apply_options(vmu, options_string);
10803
10804 if (!ast_test_flag(vmu, VM_ATTACH)) {
10805 ast_test_status_update(test, "Parse failure for attach option\n");
10806 res = 1;
10807 }
10808 if (strcasecmp(vmu->attachfmt, "wav49")) {
10809 ast_test_status_update(test, "Parse failure for attachftm option\n");
10810 res = 1;
10811 }
10812 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10813 ast_test_status_update(test, "Parse failure for serveremail option\n");
10814 res = 1;
10815 }
10816 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10817 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10818 res = 1;
10819 }
10820 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10821 ast_test_status_update(test, "Parse failure for emailbody option\n");
10822 res = 1;
10823 }
10824 if (strcasecmp(vmu->zonetag, "central")) {
10825 ast_test_status_update(test, "Parse failure for tz option\n");
10826 res = 1;
10827 }
10828 if (!ast_test_flag(vmu, VM_DELETE)) {
10829 ast_test_status_update(test, "Parse failure for delete option\n");
10830 res = 1;
10831 }
10832 if (!ast_test_flag(vmu, VM_SAYCID)) {
10833 ast_test_status_update(test, "Parse failure for saycid option\n");
10834 res = 1;
10835 }
10836 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10837 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10838 res = 1;
10839 }
10840 if (!ast_test_flag(vmu, VM_REVIEW)) {
10841 ast_test_status_update(test, "Parse failure for review option\n");
10842 res = 1;
10843 }
10844 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10845 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10846 res = 1;
10847 }
10848 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10849 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10850 res = 1;
10851 }
10852 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10853 ast_test_status_update(test, "Parse failure for operator option\n");
10854 res = 1;
10855 }
10856 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10857 ast_test_status_update(test, "Parse failure for envelope option\n");
10858 res = 1;
10859 }
10860 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10861 ast_test_status_update(test, "Parse failure for moveheard option\n");
10862 res = 1;
10863 }
10864 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10865 ast_test_status_update(test, "Parse failure for sayduration option\n");
10866 res = 1;
10867 }
10868 if (vmu->saydurationm != 5) {
10869 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10870 res = 1;
10871 }
10872 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10873 ast_test_status_update(test, "Parse failure for forcename option\n");
10874 res = 1;
10875 }
10876 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10877 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10878 res = 1;
10879 }
10880 if (strcasecmp(vmu->callback, "somecontext")) {
10881 ast_test_status_update(test, "Parse failure for callbacks option\n");
10882 res = 1;
10883 }
10884 if (strcasecmp(vmu->dialout, "somecontext2")) {
10885 ast_test_status_update(test, "Parse failure for dialout option\n");
10886 res = 1;
10887 }
10888 if (strcasecmp(vmu->exit, "somecontext3")) {
10889 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10890 res = 1;
10891 }
10892 if (vmu->minsecs != 10) {
10893 ast_test_status_update(test, "Parse failure for minsecs option\n");
10894 res = 1;
10895 }
10896 if (vmu->maxsecs != 100) {
10897 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10898 res = 1;
10899 }
10900 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10901 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10902 res = 1;
10903 }
10904 if (vmu->maxdeletedmsg != 50) {
10905 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10906 res = 1;
10907 }
10908 if (vmu->volgain != 1.3) {
10909 ast_test_status_update(test, "Parse failure for volgain option\n");
10910 res = 1;
10911 }
10912 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10913 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10914 res = 1;
10915 }
10916 #ifdef IMAP_STORAGE
10917 apply_options(vmu, option_string2);
10918
10919 if (strcasecmp(vmu->imapuser, "imapuser")) {
10920 ast_test_status_update(test, "Parse failure for imapuser option\n");
10921 res = 1;
10922 }
10923 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10924 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10925 res = 1;
10926 }
10927 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10928 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10929 res = 1;
10930 }
10931 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10932 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10933 res = 1;
10934 }
10935 #endif
10936
10937 free_user(vmu);
10938 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10939 }
10940
10941 static int vm_box_exists(struct ast_channel *chan, const char *data)
10942 {
10943 struct ast_vm_user svm;
10944 char *context, *box;
10945 AST_DECLARE_APP_ARGS(args,
10946 AST_APP_ARG(mbox);
10947 AST_APP_ARG(options);
10948 );
10949 static int dep_warning = 0;
10950
10951 if (ast_strlen_zero(data)) {
10952 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10953 return -1;
10954 }
10955
10956 if (!dep_warning) {
10957 dep_warning = 1;
10958 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10959 }
10960
10961 box = ast_strdupa(data);
10962
10963 AST_STANDARD_APP_ARGS(args, box);
10964
10965 if (args.options) {
10966 }
10967
10968 if ((context = strchr(args.mbox, '@'))) {
10969 *context = '\0';
10970 context++;
10971 }
10972
10973 if (find_user(&svm, context, args.mbox)) {
10974 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
10975 } else
10976 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
10977
10978 return 0;
10979 }
10980
10981 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
10982 {
10983 struct ast_vm_user svm;
10984 AST_DECLARE_APP_ARGS(arg,
10985 AST_APP_ARG(mbox);
10986 AST_APP_ARG(context);
10987 );
10988
10989 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
10990
10991 if (ast_strlen_zero(arg.mbox)) {
10992 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
10993 return -1;
10994 }
10995
10996 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
10997 return 0;
10998 }
10999
11000 static struct ast_custom_function mailbox_exists_acf = {
11001 .name = "MAILBOX_EXISTS",
11002 .read = acf_mailbox_exists,
11003 };
11004
11005 static int vmauthenticate(struct ast_channel *chan, const char *data)
11006 {
11007 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11008 struct ast_vm_user vmus;
11009 char *options = NULL;
11010 int silent = 0, skipuser = 0;
11011 int res = -1;
11012
11013 if (data) {
11014 s = ast_strdupa(data);
11015 user = strsep(&s, ",");
11016 options = strsep(&s, ",");
11017 if (user) {
11018 s = user;
11019 user = strsep(&s, "@");
11020 context = strsep(&s, "");
11021 if (!ast_strlen_zero(user))
11022 skipuser++;
11023 ast_copy_string(mailbox, user, sizeof(mailbox));
11024 }
11025 }
11026
11027 if (options) {
11028 silent = (strchr(options, 's')) != NULL;
11029 }
11030
11031 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11032 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11033 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11034 ast_play_and_wait(chan, "auth-thankyou");
11035 res = 0;
11036 } else if (mailbox[0] == '*') {
11037
11038 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11039 res = 0;
11040 }
11041 }
11042
11043 return res;
11044 }
11045
11046 static char *show_users_realtime(int fd, const char *context)
11047 {
11048 struct ast_config *cfg;
11049 const char *cat = NULL;
11050
11051 if (!(cfg = ast_load_realtime_multientry("voicemail",
11052 "context", context, SENTINEL))) {
11053 return CLI_FAILURE;
11054 }
11055
11056 ast_cli(fd,
11057 "\n"
11058 "=============================================================\n"
11059 "=== Configured Voicemail Users ==============================\n"
11060 "=============================================================\n"
11061 "===\n");
11062
11063 while ((cat = ast_category_browse(cfg, cat))) {
11064 struct ast_variable *var = NULL;
11065 ast_cli(fd,
11066 "=== Mailbox ...\n"
11067 "===\n");
11068 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11069 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11070 ast_cli(fd,
11071 "===\n"
11072 "=== ---------------------------------------------------------\n"
11073 "===\n");
11074 }
11075
11076 ast_cli(fd,
11077 "=============================================================\n"
11078 "\n");
11079
11080 ast_config_destroy(cfg);
11081
11082 return CLI_SUCCESS;
11083 }
11084
11085 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11086 {
11087 int which = 0;
11088 int wordlen;
11089 struct ast_vm_user *vmu;
11090 const char *context = "";
11091
11092
11093 if (pos > 4)
11094 return NULL;
11095 if (pos == 3)
11096 return (state == 0) ? ast_strdup("for") : NULL;
11097 wordlen = strlen(word);
11098 AST_LIST_TRAVERSE(&users, vmu, list) {
11099 if (!strncasecmp(word, vmu->context, wordlen)) {
11100 if (context && strcmp(context, vmu->context) && ++which > state)
11101 return ast_strdup(vmu->context);
11102
11103 context = vmu->context;
11104 }
11105 }
11106 return NULL;
11107 }
11108
11109
11110 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11111 {
11112 struct ast_vm_user *vmu;
11113 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11114 const char *context = NULL;
11115 int users_counter = 0;
11116
11117 switch (cmd) {
11118 case CLI_INIT:
11119 e->command = "voicemail show users";
11120 e->usage =
11121 "Usage: voicemail show users [for <context>]\n"
11122 " Lists all mailboxes currently set up\n";
11123 return NULL;
11124 case CLI_GENERATE:
11125 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11126 }
11127
11128 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11129 return CLI_SHOWUSAGE;
11130 if (a->argc == 5) {
11131 if (strcmp(a->argv[3],"for"))
11132 return CLI_SHOWUSAGE;
11133 context = a->argv[4];
11134 }
11135
11136 if (ast_check_realtime("voicemail")) {
11137 if (!context) {
11138 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11139 return CLI_SHOWUSAGE;
11140 }
11141 return show_users_realtime(a->fd, context);
11142 }
11143
11144 AST_LIST_LOCK(&users);
11145 if (AST_LIST_EMPTY(&users)) {
11146 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11147 AST_LIST_UNLOCK(&users);
11148 return CLI_FAILURE;
11149 }
11150 if (a->argc == 3)
11151 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11152 else {
11153 int count = 0;
11154 AST_LIST_TRAVERSE(&users, vmu, list) {
11155 if (!strcmp(context, vmu->context))
11156 count++;
11157 }
11158 if (count) {
11159 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11160 } else {
11161 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11162 AST_LIST_UNLOCK(&users);
11163 return CLI_FAILURE;
11164 }
11165 }
11166 AST_LIST_TRAVERSE(&users, vmu, list) {
11167 int newmsgs = 0, oldmsgs = 0;
11168 char count[12], tmp[256] = "";
11169
11170 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
11171 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11172 inboxcount(tmp, &newmsgs, &oldmsgs);
11173 snprintf(count, sizeof(count), "%d", newmsgs);
11174 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11175 users_counter++;
11176 }
11177 }
11178 AST_LIST_UNLOCK(&users);
11179 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11180 return CLI_SUCCESS;
11181 }
11182
11183
11184 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11185 {
11186 struct vm_zone *zone;
11187 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11188 char *res = CLI_SUCCESS;
11189
11190 switch (cmd) {
11191 case CLI_INIT:
11192 e->command = "voicemail show zones";
11193 e->usage =
11194 "Usage: voicemail show zones\n"
11195 " Lists zone message formats\n";
11196 return NULL;
11197 case CLI_GENERATE:
11198 return NULL;
11199 }
11200
11201 if (a->argc != 3)
11202 return CLI_SHOWUSAGE;
11203
11204 AST_LIST_LOCK(&zones);
11205 if (!AST_LIST_EMPTY(&zones)) {
11206 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11207 AST_LIST_TRAVERSE(&zones, zone, list) {
11208 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11209 }
11210 } else {
11211 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11212 res = CLI_FAILURE;
11213 }
11214 AST_LIST_UNLOCK(&zones);
11215
11216 return res;
11217 }
11218
11219
11220 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11221 {
11222 switch (cmd) {
11223 case CLI_INIT:
11224 e->command = "voicemail reload";
11225 e->usage =
11226 "Usage: voicemail reload\n"
11227 " Reload voicemail configuration\n";
11228 return NULL;
11229 case CLI_GENERATE:
11230 return NULL;
11231 }
11232
11233 if (a->argc != 2)
11234 return CLI_SHOWUSAGE;
11235
11236 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11237 load_config(1);
11238
11239 return CLI_SUCCESS;
11240 }
11241
11242 static struct ast_cli_entry cli_voicemail[] = {
11243 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11244 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11245 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11246 };
11247
11248 #ifdef IMAP_STORAGE
11249 #define DATA_EXPORT_VM_USERS(USER) \
11250 USER(ast_vm_user, context, AST_DATA_STRING) \
11251 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11252 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11253 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11254 USER(ast_vm_user, email, AST_DATA_STRING) \
11255 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11256 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11257 USER(ast_vm_user, pager, AST_DATA_STRING) \
11258 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11259 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11260 USER(ast_vm_user, language, AST_DATA_STRING) \
11261 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11262 USER(ast_vm_user, callback, AST_DATA_STRING) \
11263 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11264 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11265 USER(ast_vm_user, exit, AST_DATA_STRING) \
11266 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11267 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11268 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11269 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11270 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11271 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11272 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11273 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11274 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11275 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11276 #else
11277 #define DATA_EXPORT_VM_USERS(USER) \
11278 USER(ast_vm_user, context, AST_DATA_STRING) \
11279 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11280 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11281 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11282 USER(ast_vm_user, email, AST_DATA_STRING) \
11283 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11284 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11285 USER(ast_vm_user, pager, AST_DATA_STRING) \
11286 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11287 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11288 USER(ast_vm_user, language, AST_DATA_STRING) \
11289 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11290 USER(ast_vm_user, callback, AST_DATA_STRING) \
11291 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11292 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11293 USER(ast_vm_user, exit, AST_DATA_STRING) \
11294 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11295 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11296 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11297 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11298 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11299 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11300 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11301 #endif
11302
11303 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11304
11305 #define DATA_EXPORT_VM_ZONES(ZONE) \
11306 ZONE(vm_zone, name, AST_DATA_STRING) \
11307 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11308 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11309
11310 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11311
11312
11313
11314
11315
11316
11317
11318
11319 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11320 struct ast_data *data_root, struct ast_vm_user *user)
11321 {
11322 struct ast_data *data_user, *data_zone;
11323 struct ast_data *data_state;
11324 struct vm_zone *zone = NULL;
11325 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11326 char ext_context[256] = "";
11327
11328 data_user = ast_data_add_node(data_root, "user");
11329 if (!data_user) {
11330 return -1;
11331 }
11332
11333 ast_data_add_structure(ast_vm_user, data_user, user);
11334
11335 AST_LIST_LOCK(&zones);
11336 AST_LIST_TRAVERSE(&zones, zone, list) {
11337 if (!strcmp(zone->name, user->zonetag)) {
11338 break;
11339 }
11340 }
11341 AST_LIST_UNLOCK(&zones);
11342
11343
11344 data_state = ast_data_add_node(data_user, "state");
11345 if (!data_state) {
11346 return -1;
11347 }
11348 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11349 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11350 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11351 ast_data_add_int(data_state, "newmsg", newmsg);
11352 ast_data_add_int(data_state, "oldmsg", oldmsg);
11353
11354 if (zone) {
11355 data_zone = ast_data_add_node(data_user, "zone");
11356 ast_data_add_structure(vm_zone, data_zone, zone);
11357 }
11358
11359 if (!ast_data_search_match(search, data_user)) {
11360 ast_data_remove_node(data_root, data_user);
11361 }
11362
11363 return 0;
11364 }
11365
11366 static int vm_users_data_provider_get(const struct ast_data_search *search,
11367 struct ast_data *data_root)
11368 {
11369 struct ast_vm_user *user;
11370
11371 AST_LIST_LOCK(&users);
11372 AST_LIST_TRAVERSE(&users, user, list) {
11373 vm_users_data_provider_get_helper(search, data_root, user);
11374 }
11375 AST_LIST_UNLOCK(&users);
11376
11377 return 0;
11378 }
11379
11380 static const struct ast_data_handler vm_users_data_provider = {
11381 .version = AST_DATA_HANDLER_VERSION,
11382 .get = vm_users_data_provider_get
11383 };
11384
11385 static const struct ast_data_entry vm_data_providers[] = {
11386 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11387 };
11388
11389 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11390 {
11391 int new = 0, old = 0, urgent = 0;
11392
11393 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11394
11395 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11396 mwi_sub->old_urgent = urgent;
11397 mwi_sub->old_new = new;
11398 mwi_sub->old_old = old;
11399 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11400 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11401 }
11402 }
11403
11404 static void poll_subscribed_mailboxes(void)
11405 {
11406 struct mwi_sub *mwi_sub;
11407
11408 AST_RWLIST_RDLOCK(&mwi_subs);
11409 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11410 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11411 poll_subscribed_mailbox(mwi_sub);
11412 }
11413 }
11414 AST_RWLIST_UNLOCK(&mwi_subs);
11415 }
11416
11417 static void *mb_poll_thread(void *data)
11418 {
11419 while (poll_thread_run) {
11420 struct timespec ts = { 0, };
11421 struct timeval wait;
11422
11423 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11424 ts.tv_sec = wait.tv_sec;
11425 ts.tv_nsec = wait.tv_usec * 1000;
11426
11427 ast_mutex_lock(&poll_lock);
11428 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11429 ast_mutex_unlock(&poll_lock);
11430
11431 if (!poll_thread_run)
11432 break;
11433
11434 poll_subscribed_mailboxes();
11435 }
11436
11437 return NULL;
11438 }
11439
11440 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11441 {
11442 ast_free(mwi_sub);
11443 }
11444
11445 static int handle_unsubscribe(void *datap)
11446 {
11447 struct mwi_sub *mwi_sub;
11448 uint32_t *uniqueid = datap;
11449
11450 AST_RWLIST_WRLOCK(&mwi_subs);
11451 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11452 if (mwi_sub->uniqueid == *uniqueid) {
11453 AST_LIST_REMOVE_CURRENT(entry);
11454 break;
11455 }
11456 }
11457 AST_RWLIST_TRAVERSE_SAFE_END
11458 AST_RWLIST_UNLOCK(&mwi_subs);
11459
11460 if (mwi_sub)
11461 mwi_sub_destroy(mwi_sub);
11462
11463 ast_free(uniqueid);
11464 return 0;
11465 }
11466
11467 static int handle_subscribe(void *datap)
11468 {
11469 unsigned int len;
11470 struct mwi_sub *mwi_sub;
11471 struct mwi_sub_task *p = datap;
11472
11473 len = sizeof(*mwi_sub);
11474 if (!ast_strlen_zero(p->mailbox))
11475 len += strlen(p->mailbox);
11476
11477 if (!ast_strlen_zero(p->context))
11478 len += strlen(p->context) + 1;
11479
11480 if (!(mwi_sub = ast_calloc(1, len)))
11481 return -1;
11482
11483 mwi_sub->uniqueid = p->uniqueid;
11484 if (!ast_strlen_zero(p->mailbox))
11485 strcpy(mwi_sub->mailbox, p->mailbox);
11486
11487 if (!ast_strlen_zero(p->context)) {
11488 strcat(mwi_sub->mailbox, "@");
11489 strcat(mwi_sub->mailbox, p->context);
11490 }
11491
11492 AST_RWLIST_WRLOCK(&mwi_subs);
11493 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11494 AST_RWLIST_UNLOCK(&mwi_subs);
11495 ast_free((void *) p->mailbox);
11496 ast_free((void *) p->context);
11497 ast_free(p);
11498 poll_subscribed_mailbox(mwi_sub);
11499 return 0;
11500 }
11501
11502 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11503 {
11504 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11505 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
11506 return;
11507
11508 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11509 return;
11510
11511 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11512 *uniqueid = u;
11513 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11514 ast_free(uniqueid);
11515 }
11516 }
11517
11518 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11519 {
11520 struct mwi_sub_task *mwist;
11521
11522 if (ast_event_get_type(event) != AST_EVENT_SUB)
11523 return;
11524
11525 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11526 return;
11527
11528 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11529 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11530 return;
11531 }
11532 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11533 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11534 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11535
11536 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11537 ast_free(mwist);
11538 }
11539 }
11540
11541 static void start_poll_thread(void)
11542 {
11543 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11544 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11545 AST_EVENT_IE_END);
11546
11547 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11548 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11549 AST_EVENT_IE_END);
11550
11551 if (mwi_sub_sub)
11552 ast_event_report_subs(mwi_sub_sub);
11553
11554 poll_thread_run = 1;
11555
11556 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
11557 }
11558
11559 static void stop_poll_thread(void)
11560 {
11561 poll_thread_run = 0;
11562
11563 if (mwi_sub_sub) {
11564 ast_event_unsubscribe(mwi_sub_sub);
11565 mwi_sub_sub = NULL;
11566 }
11567
11568 if (mwi_unsub_sub) {
11569 ast_event_unsubscribe(mwi_unsub_sub);
11570 mwi_unsub_sub = NULL;
11571 }
11572
11573 ast_mutex_lock(&poll_lock);
11574 ast_cond_signal(&poll_cond);
11575 ast_mutex_unlock(&poll_lock);
11576
11577 pthread_join(poll_thread, NULL);
11578
11579 poll_thread = AST_PTHREADT_NULL;
11580 }
11581
11582
11583 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11584 {
11585 struct ast_vm_user *vmu = NULL;
11586 const char *id = astman_get_header(m, "ActionID");
11587 char actionid[128] = "";
11588
11589 if (!ast_strlen_zero(id))
11590 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11591
11592 AST_LIST_LOCK(&users);
11593
11594 if (AST_LIST_EMPTY(&users)) {
11595 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11596 AST_LIST_UNLOCK(&users);
11597 return RESULT_SUCCESS;
11598 }
11599
11600 astman_send_ack(s, m, "Voicemail user list will follow");
11601
11602 AST_LIST_TRAVERSE(&users, vmu, list) {
11603 char dirname[256];
11604
11605 #ifdef IMAP_STORAGE
11606 int new, old;
11607 inboxcount(vmu->mailbox, &new, &old);
11608 #endif
11609
11610 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11611 astman_append(s,
11612 "%s"
11613 "Event: VoicemailUserEntry\r\n"
11614 "VMContext: %s\r\n"
11615 "VoiceMailbox: %s\r\n"
11616 "Fullname: %s\r\n"
11617 "Email: %s\r\n"
11618 "Pager: %s\r\n"
11619 "ServerEmail: %s\r\n"
11620 "MailCommand: %s\r\n"
11621 "Language: %s\r\n"
11622 "TimeZone: %s\r\n"
11623 "Callback: %s\r\n"
11624 "Dialout: %s\r\n"
11625 "UniqueID: %s\r\n"
11626 "ExitContext: %s\r\n"
11627 "SayDurationMinimum: %d\r\n"
11628 "SayEnvelope: %s\r\n"
11629 "SayCID: %s\r\n"
11630 "AttachMessage: %s\r\n"
11631 "AttachmentFormat: %s\r\n"
11632 "DeleteMessage: %s\r\n"
11633 "VolumeGain: %.2f\r\n"
11634 "CanReview: %s\r\n"
11635 "CallOperator: %s\r\n"
11636 "MaxMessageCount: %d\r\n"
11637 "MaxMessageLength: %d\r\n"
11638 "NewMessageCount: %d\r\n"
11639 #ifdef IMAP_STORAGE
11640 "OldMessageCount: %d\r\n"
11641 "IMAPUser: %s\r\n"
11642 #endif
11643 "\r\n",
11644 actionid,
11645 vmu->context,
11646 vmu->mailbox,
11647 vmu->fullname,
11648 vmu->email,
11649 vmu->pager,
11650 vmu->serveremail,
11651 vmu->mailcmd,
11652 vmu->language,
11653 vmu->zonetag,
11654 vmu->callback,
11655 vmu->dialout,
11656 vmu->uniqueid,
11657 vmu->exit,
11658 vmu->saydurationm,
11659 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11660 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11661 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11662 vmu->attachfmt,
11663 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11664 vmu->volgain,
11665 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11666 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11667 vmu->maxmsg,
11668 vmu->maxsecs,
11669 #ifdef IMAP_STORAGE
11670 new, old, vmu->imapuser
11671 #else
11672 count_messages(vmu, dirname)
11673 #endif
11674 );
11675 }
11676 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11677
11678 AST_LIST_UNLOCK(&users);
11679
11680 return RESULT_SUCCESS;
11681 }
11682
11683
11684 static void free_vm_users(void)
11685 {
11686 struct ast_vm_user *current;
11687 AST_LIST_LOCK(&users);
11688 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11689 ast_set_flag(current, VM_ALLOCED);
11690 free_user(current);
11691 }
11692 AST_LIST_UNLOCK(&users);
11693 }
11694
11695
11696 static void free_vm_zones(void)
11697 {
11698 struct vm_zone *zcur;
11699 AST_LIST_LOCK(&zones);
11700 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11701 free_zone(zcur);
11702 AST_LIST_UNLOCK(&zones);
11703 }
11704
11705 static const char *substitute_escapes(const char *value)
11706 {
11707 char *current;
11708
11709
11710 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11711
11712 ast_str_reset(str);
11713
11714
11715 for (current = (char *) value; *current; current++) {
11716 if (*current == '\\') {
11717 current++;
11718 if (!*current) {
11719 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11720 break;
11721 }
11722 switch (*current) {
11723 case '\\':
11724 ast_str_append(&str, 0, "\\");
11725 break;
11726 case 'r':
11727 ast_str_append(&str, 0, "\r");
11728 break;
11729 case 'n':
11730 #ifdef IMAP_STORAGE
11731 if (!str->used || str->str[str->used - 1] != '\r') {
11732 ast_str_append(&str, 0, "\r");
11733 }
11734 #endif
11735 ast_str_append(&str, 0, "\n");
11736 break;
11737 case 't':
11738 ast_str_append(&str, 0, "\t");
11739 break;
11740 default:
11741 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11742 break;
11743 }
11744 } else {
11745 ast_str_append(&str, 0, "%c", *current);
11746 }
11747 }
11748
11749 return ast_str_buffer(str);
11750 }
11751
11752 static int load_config(int reload)
11753 {
11754 struct ast_config *cfg, *ucfg;
11755 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11756 int res;
11757
11758 ast_unload_realtime("voicemail");
11759 ast_unload_realtime("voicemail_data");
11760
11761 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11762 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11763 return 0;
11764 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11765 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11766 ucfg = NULL;
11767 }
11768 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11769 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11770 ast_config_destroy(ucfg);
11771 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11772 return 0;
11773 }
11774 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11775 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11776 return 0;
11777 } else {
11778 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11779 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11780 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11781 ucfg = NULL;
11782 }
11783 }
11784
11785 res = actual_load_config(reload, cfg, ucfg);
11786
11787 ast_config_destroy(cfg);
11788 ast_config_destroy(ucfg);
11789
11790 return res;
11791 }
11792
11793 #ifdef TEST_FRAMEWORK
11794 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11795 {
11796 ast_unload_realtime("voicemail");
11797 ast_unload_realtime("voicemail_data");
11798 return actual_load_config(reload, cfg, ucfg);
11799 }
11800 #endif
11801
11802 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11803 {
11804 struct ast_vm_user *current;
11805 char *cat;
11806 struct ast_variable *var;
11807 const char *val;
11808 char *q, *stringp, *tmp;
11809 int x;
11810 int tmpadsi[4];
11811 char secretfn[PATH_MAX] = "";
11812
11813 #ifdef IMAP_STORAGE
11814 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11815 #endif
11816
11817 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11818 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11819 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11820 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11821 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11822
11823
11824 free_vm_users();
11825
11826
11827 free_vm_zones();
11828
11829 AST_LIST_LOCK(&users);
11830
11831 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11832 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11833
11834 if (cfg) {
11835
11836
11837 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11838 val = "default";
11839 ast_copy_string(userscontext, val, sizeof(userscontext));
11840
11841 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11842 val = "yes";
11843 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11844
11845 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11846 val = "no";
11847 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11848
11849 volgain = 0.0;
11850 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11851 sscanf(val, "%30lf", &volgain);
11852
11853 #ifdef ODBC_STORAGE
11854 strcpy(odbc_database, "asterisk");
11855 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11856 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11857 }
11858 strcpy(odbc_table, "voicemessages");
11859 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11860 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11861 }
11862 #endif
11863
11864 strcpy(mailcmd, SENDMAIL);
11865 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11866 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11867
11868 maxsilence = 0;
11869 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11870 maxsilence = atoi(val);
11871 if (maxsilence > 0)
11872 maxsilence *= 1000;
11873 }
11874
11875 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11876 maxmsg = MAXMSG;
11877 } else {
11878 maxmsg = atoi(val);
11879 if (maxmsg < 0) {
11880 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11881 maxmsg = MAXMSG;
11882 } else if (maxmsg > MAXMSGLIMIT) {
11883 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11884 maxmsg = MAXMSGLIMIT;
11885 }
11886 }
11887
11888 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11889 maxdeletedmsg = 0;
11890 } else {
11891 if (sscanf(val, "%30d", &x) == 1)
11892 maxdeletedmsg = x;
11893 else if (ast_true(val))
11894 maxdeletedmsg = MAXMSG;
11895 else
11896 maxdeletedmsg = 0;
11897
11898 if (maxdeletedmsg < 0) {
11899 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11900 maxdeletedmsg = MAXMSG;
11901 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11902 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11903 maxdeletedmsg = MAXMSGLIMIT;
11904 }
11905 }
11906
11907
11908 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11909 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11910 }
11911
11912
11913 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11914 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11915 }
11916
11917
11918 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11919 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11920 pwdchange = PWDCHANGE_EXTERNAL;
11921 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11922 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11923 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11924 }
11925
11926
11927 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11928 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11929 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11930 }
11931
11932 #ifdef IMAP_STORAGE
11933
11934 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11935 ast_copy_string(imapserver, val, sizeof(imapserver));
11936 } else {
11937 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11938 }
11939
11940 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11941 ast_copy_string(imapport, val, sizeof(imapport));
11942 } else {
11943 ast_copy_string(imapport, "143", sizeof(imapport));
11944 }
11945
11946 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11947 ast_copy_string(imapflags, val, sizeof(imapflags));
11948 }
11949
11950 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11951 ast_copy_string(authuser, val, sizeof(authuser));
11952 }
11953
11954 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11955 ast_copy_string(authpassword, val, sizeof(authpassword));
11956 }
11957
11958 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11959 if (ast_false(val))
11960 expungeonhangup = 0;
11961 else
11962 expungeonhangup = 1;
11963 } else {
11964 expungeonhangup = 1;
11965 }
11966
11967 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
11968 ast_copy_string(imapfolder, val, sizeof(imapfolder));
11969 } else {
11970 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
11971 }
11972 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
11973 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
11974 }
11975 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
11976 imapgreetings = ast_true(val);
11977 } else {
11978 imapgreetings = 0;
11979 }
11980 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
11981 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11982 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
11983
11984 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11985 } else {
11986 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
11987 }
11988
11989
11990
11991
11992
11993 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
11994 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
11995 } else {
11996 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
11997 }
11998
11999 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12000 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12001 } else {
12002 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12003 }
12004
12005 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12006 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12007 } else {
12008 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12009 }
12010
12011 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12012 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12013 } else {
12014 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12015 }
12016
12017
12018 imapversion++;
12019 #endif
12020
12021 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12022 ast_copy_string(externnotify, val, sizeof(externnotify));
12023 ast_debug(1, "found externnotify: %s\n", externnotify);
12024 } else {
12025 externnotify[0] = '\0';
12026 }
12027
12028
12029 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12030 ast_debug(1, "Enabled SMDI voicemail notification\n");
12031 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12032 smdi_iface = ast_smdi_interface_find(val);
12033 } else {
12034 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12035 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12036 }
12037 if (!smdi_iface) {
12038 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12039 }
12040 }
12041
12042
12043 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12044 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12045 silencethreshold = atoi(val);
12046
12047 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12048 val = ASTERISK_USERNAME;
12049 ast_copy_string(serveremail, val, sizeof(serveremail));
12050
12051 vmmaxsecs = 0;
12052 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12053 if (sscanf(val, "%30d", &x) == 1) {
12054 vmmaxsecs = x;
12055 } else {
12056 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12057 }
12058 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12059 static int maxmessage_deprecate = 0;
12060 if (maxmessage_deprecate == 0) {
12061 maxmessage_deprecate = 1;
12062 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12063 }
12064 if (sscanf(val, "%30d", &x) == 1) {
12065 vmmaxsecs = x;
12066 } else {
12067 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12068 }
12069 }
12070
12071 vmminsecs = 0;
12072 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12073 if (sscanf(val, "%30d", &x) == 1) {
12074 vmminsecs = x;
12075 if (maxsilence / 1000 >= vmminsecs) {
12076 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12077 }
12078 } else {
12079 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12080 }
12081 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12082 static int maxmessage_deprecate = 0;
12083 if (maxmessage_deprecate == 0) {
12084 maxmessage_deprecate = 1;
12085 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12086 }
12087 if (sscanf(val, "%30d", &x) == 1) {
12088 vmminsecs = x;
12089 if (maxsilence / 1000 >= vmminsecs) {
12090 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12091 }
12092 } else {
12093 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12094 }
12095 }
12096
12097 val = ast_variable_retrieve(cfg, "general", "format");
12098 if (!val) {
12099 val = "wav";
12100 } else {
12101 tmp = ast_strdupa(val);
12102 val = ast_format_str_reduce(tmp);
12103 if (!val) {
12104 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12105 val = "wav";
12106 }
12107 }
12108 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12109
12110 skipms = 3000;
12111 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12112 if (sscanf(val, "%30d", &x) == 1) {
12113 maxgreet = x;
12114 } else {
12115 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12116 }
12117 }
12118
12119 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12120 if (sscanf(val, "%30d", &x) == 1) {
12121 skipms = x;
12122 } else {
12123 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12124 }
12125 }
12126
12127 maxlogins = 3;
12128 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12129 if (sscanf(val, "%30d", &x) == 1) {
12130 maxlogins = x;
12131 } else {
12132 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12133 }
12134 }
12135
12136 minpassword = MINPASSWORD;
12137 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12138 if (sscanf(val, "%30d", &x) == 1) {
12139 minpassword = x;
12140 } else {
12141 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12142 }
12143 }
12144
12145
12146 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12147 val = "no";
12148 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12149
12150
12151 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12152 val = "no";
12153 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12154
12155 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12156 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12157 stringp = ast_strdupa(val);
12158 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12159 if (!ast_strlen_zero(stringp)) {
12160 q = strsep(&stringp, ",");
12161 while ((*q == ' ')||(*q == '\t'))
12162 q++;
12163 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12164 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12165 } else {
12166 cidinternalcontexts[x][0] = '\0';
12167 }
12168 }
12169 }
12170 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12171 ast_debug(1, "VM Review Option disabled globally\n");
12172 val = "no";
12173 }
12174 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12175
12176
12177 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12178 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12179 val = "no";
12180 } else {
12181 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12182 }
12183 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12184 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12185 ast_debug(1, "VM next message wrap disabled globally\n");
12186 val = "no";
12187 }
12188 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12189
12190 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12191 ast_debug(1, "VM Operator break disabled globally\n");
12192 val = "no";
12193 }
12194 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12195
12196 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12197 ast_debug(1, "VM CID Info before msg disabled globally\n");
12198 val = "no";
12199 }
12200 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12201
12202 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12203 ast_debug(1, "Send Voicemail msg disabled globally\n");
12204 val = "no";
12205 }
12206 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12207
12208 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12209 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12210 val = "yes";
12211 }
12212 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12213
12214 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12215 ast_debug(1, "Move Heard enabled globally\n");
12216 val = "yes";
12217 }
12218 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12219
12220 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12221 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12222 val = "no";
12223 }
12224 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12225
12226 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12227 ast_debug(1, "Duration info before msg enabled globally\n");
12228 val = "yes";
12229 }
12230 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12231
12232 saydurationminfo = 2;
12233 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12234 if (sscanf(val, "%30d", &x) == 1) {
12235 saydurationminfo = x;
12236 } else {
12237 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12238 }
12239 }
12240
12241 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12242 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12243 val = "no";
12244 }
12245 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12246
12247 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12248 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12249 ast_debug(1, "found dialout context: %s\n", dialcontext);
12250 } else {
12251 dialcontext[0] = '\0';
12252 }
12253
12254 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12255 ast_copy_string(callcontext, val, sizeof(callcontext));
12256 ast_debug(1, "found callback context: %s\n", callcontext);
12257 } else {
12258 callcontext[0] = '\0';
12259 }
12260
12261 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12262 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12263 ast_debug(1, "found operator context: %s\n", exitcontext);
12264 } else {
12265 exitcontext[0] = '\0';
12266 }
12267
12268
12269 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12270 ast_copy_string(vm_password, val, sizeof(vm_password));
12271 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12272 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12273 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12274 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12275 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12276 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12277 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12278 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12279 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12280 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12281 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12282 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12283 }
12284 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12285 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12286 }
12287
12288 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12289 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12290 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12291 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12292 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12293 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12294 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12295 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12296 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12297 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12298
12299 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12300 val = "no";
12301 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12302
12303 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12304 val = "voicemail.conf";
12305 }
12306 if (!(strcmp(val, "spooldir"))) {
12307 passwordlocation = OPT_PWLOC_SPOOLDIR;
12308 } else {
12309 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12310 }
12311
12312 poll_freq = DEFAULT_POLL_FREQ;
12313 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12314 if (sscanf(val, "%30u", &poll_freq) != 1) {
12315 poll_freq = DEFAULT_POLL_FREQ;
12316 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12317 }
12318 }
12319
12320 poll_mailboxes = 0;
12321 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12322 poll_mailboxes = ast_true(val);
12323
12324 memset(fromstring, 0, sizeof(fromstring));
12325 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12326 strcpy(charset, "ISO-8859-1");
12327 if (emailbody) {
12328 ast_free(emailbody);
12329 emailbody = NULL;
12330 }
12331 if (emailsubject) {
12332 ast_free(emailsubject);
12333 emailsubject = NULL;
12334 }
12335 if (pagerbody) {
12336 ast_free(pagerbody);
12337 pagerbody = NULL;
12338 }
12339 if (pagersubject) {
12340 ast_free(pagersubject);
12341 pagersubject = NULL;
12342 }
12343 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12344 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12345 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12346 ast_copy_string(fromstring, val, sizeof(fromstring));
12347 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12348 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12349 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12350 ast_copy_string(charset, val, sizeof(charset));
12351 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12352 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12353 for (x = 0; x < 4; x++) {
12354 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12355 }
12356 }
12357 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12358 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12359 for (x = 0; x < 4; x++) {
12360 memcpy(&adsisec[x], &tmpadsi[x], 1);
12361 }
12362 }
12363 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12364 if (atoi(val)) {
12365 adsiver = atoi(val);
12366 }
12367 }
12368 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12369 ast_copy_string(zonetag, val, sizeof(zonetag));
12370 }
12371 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12372 ast_copy_string(locale, val, sizeof(locale));
12373 }
12374 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12375 emailsubject = ast_strdup(substitute_escapes(val));
12376 }
12377 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12378 emailbody = ast_strdup(substitute_escapes(val));
12379 }
12380 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12381 pagersubject = ast_strdup(substitute_escapes(val));
12382 }
12383 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12384 pagerbody = ast_strdup(substitute_escapes(val));
12385 }
12386
12387
12388 if (ucfg) {
12389 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12390 if (!strcasecmp(cat, "general")) {
12391 continue;
12392 }
12393 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12394 continue;
12395 if ((current = find_or_create(userscontext, cat))) {
12396 populate_defaults(current);
12397 apply_options_full(current, ast_variable_browse(ucfg, cat));
12398 ast_copy_string(current->context, userscontext, sizeof(current->context));
12399 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12400 current->passwordlocation = OPT_PWLOC_USERSCONF;
12401 }
12402
12403 switch (current->passwordlocation) {
12404 case OPT_PWLOC_SPOOLDIR:
12405 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12406 read_password_from_file(secretfn, current->password, sizeof(current->password));
12407 }
12408 }
12409 }
12410 }
12411
12412
12413 cat = ast_category_browse(cfg, NULL);
12414 while (cat) {
12415 if (strcasecmp(cat, "general")) {
12416 var = ast_variable_browse(cfg, cat);
12417 if (strcasecmp(cat, "zonemessages")) {
12418
12419 while (var) {
12420 append_mailbox(cat, var->name, var->value);
12421 var = var->next;
12422 }
12423 } else {
12424
12425 while (var) {
12426 struct vm_zone *z;
12427 if ((z = ast_malloc(sizeof(*z)))) {
12428 char *msg_format, *tzone;
12429 msg_format = ast_strdupa(var->value);
12430 tzone = strsep(&msg_format, "|,");
12431 if (msg_format) {
12432 ast_copy_string(z->name, var->name, sizeof(z->name));
12433 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12434 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12435 AST_LIST_LOCK(&zones);
12436 AST_LIST_INSERT_HEAD(&zones, z, list);
12437 AST_LIST_UNLOCK(&zones);
12438 } else {
12439 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12440 ast_free(z);
12441 }
12442 } else {
12443 AST_LIST_UNLOCK(&users);
12444 return -1;
12445 }
12446 var = var->next;
12447 }
12448 }
12449 }
12450 cat = ast_category_browse(cfg, cat);
12451 }
12452
12453 AST_LIST_UNLOCK(&users);
12454
12455 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12456 start_poll_thread();
12457 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12458 stop_poll_thread();;
12459
12460 return 0;
12461 } else {
12462 AST_LIST_UNLOCK(&users);
12463 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12464 return 0;
12465 }
12466 }
12467
12468 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12469 {
12470 int res = -1;
12471 char dir[PATH_MAX];
12472 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12473 ast_debug(2, "About to try retrieving name file %s\n", dir);
12474 RETRIEVE(dir, -1, mailbox, context);
12475 if (ast_fileexists(dir, NULL, NULL)) {
12476 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12477 }
12478 DISPOSE(dir, -1);
12479 return res;
12480 }
12481
12482 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12483 struct ast_config *pwconf;
12484 struct ast_flags config_flags = { 0 };
12485
12486 pwconf = ast_config_load(secretfn, config_flags);
12487 if (pwconf) {
12488 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12489 if (val) {
12490 ast_copy_string(password, val, passwordlen);
12491 return;
12492 }
12493 }
12494 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12495 }
12496
12497 static int write_password_to_file(const char *secretfn, const char *password) {
12498 struct ast_config *conf;
12499 struct ast_category *cat;
12500 struct ast_variable *var;
12501
12502 if (!(conf=ast_config_new())) {
12503 ast_log(LOG_ERROR, "Error creating new config structure\n");
12504 return -1;
12505 }
12506 if (!(cat=ast_category_new("general","",1))) {
12507 ast_log(LOG_ERROR, "Error creating new category structure\n");
12508 return -1;
12509 }
12510 if (!(var=ast_variable_new("password",password,""))) {
12511 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12512 return -1;
12513 }
12514 ast_category_append(conf,cat);
12515 ast_variable_append(cat,var);
12516 if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12517 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12518 return -1;
12519 }
12520 return 0;
12521 }
12522
12523 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12524 {
12525 char *context;
12526 char *args_copy;
12527 int res;
12528
12529 if (ast_strlen_zero(data)) {
12530 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context");
12531 return -1;
12532 }
12533
12534 args_copy = ast_strdupa(data);
12535 if ((context = strchr(args_copy, '@'))) {
12536 *context++ = '\0';
12537 } else {
12538 context = "default";
12539 }
12540
12541 if ((res = sayname(chan, args_copy, context) < 0)) {
12542 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12543 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12544 if (!res) {
12545 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12546 }
12547 }
12548
12549 return res;
12550 }
12551
12552 #ifdef TEST_FRAMEWORK
12553 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12554 {
12555 return 0;
12556 }
12557
12558 static struct ast_frame *fake_read(struct ast_channel *ast)
12559 {
12560 return &ast_null_frame;
12561 }
12562
12563 AST_TEST_DEFINE(test_voicemail_vmsayname)
12564 {
12565 char dir[PATH_MAX];
12566 char dir2[PATH_MAX];
12567 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12568 static const char TEST_EXTENSION[] = "1234";
12569
12570 struct ast_channel *test_channel1 = NULL;
12571 int res = -1;
12572
12573 static const struct ast_channel_tech fake_tech = {
12574 .write = fake_write,
12575 .read = fake_read,
12576 };
12577
12578 switch (cmd) {
12579 case TEST_INIT:
12580 info->name = "vmsayname_exec";
12581 info->category = "/apps/app_voicemail/";
12582 info->summary = "Vmsayname unit test";
12583 info->description =
12584 "This tests passing various parameters to vmsayname";
12585 return AST_TEST_NOT_RUN;
12586 case TEST_EXECUTE:
12587 break;
12588 }
12589
12590 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12591 NULL, NULL, 0, 0, "TestChannel1"))) {
12592 goto exit_vmsayname_test;
12593 }
12594
12595
12596 test_channel1->nativeformats = AST_FORMAT_GSM;
12597 test_channel1->writeformat = AST_FORMAT_GSM;
12598 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12599 test_channel1->readformat = AST_FORMAT_GSM;
12600 test_channel1->rawreadformat = AST_FORMAT_GSM;
12601 test_channel1->tech = &fake_tech;
12602
12603 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12604 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12605 if (!(res = vmsayname_exec(test_channel1, dir))) {
12606 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12607 if (ast_fileexists(dir, NULL, NULL)) {
12608 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12609 res = -1;
12610 goto exit_vmsayname_test;
12611 } else {
12612
12613 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12614 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12615 goto exit_vmsayname_test;
12616 }
12617 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12618 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12619
12620 if ((res = symlink(dir, dir2))) {
12621 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12622 goto exit_vmsayname_test;
12623 }
12624 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12625 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12626 res = vmsayname_exec(test_channel1, dir);
12627
12628
12629 unlink(dir2);
12630 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12631 rmdir(dir2);
12632 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12633 rmdir(dir2);
12634 }
12635 }
12636
12637 exit_vmsayname_test:
12638
12639 if (test_channel1) {
12640 ast_hangup(test_channel1);
12641 }
12642
12643 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12644 }
12645
12646 AST_TEST_DEFINE(test_voicemail_msgcount)
12647 {
12648 int i, j, res = AST_TEST_PASS, syserr;
12649 struct ast_vm_user *vmu;
12650 struct vm_state vms;
12651 #ifdef IMAP_STORAGE
12652 struct ast_channel *chan = NULL;
12653 #endif
12654 struct {
12655 char dir[256];
12656 char file[256];
12657 char txtfile[256];
12658 } tmp[3];
12659 char syscmd[256];
12660 const char origweasels[] = "tt-weasels";
12661 const char testcontext[] = "test";
12662 const char testmailbox[] = "00000000";
12663 const char testspec[] = "00000000@test";
12664 FILE *txt;
12665 int new, old, urgent;
12666 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12667 const int folder2mbox[3] = { 1, 11, 0 };
12668 const int expected_results[3][12] = {
12669
12670 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12671 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12672 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12673 };
12674
12675 switch (cmd) {
12676 case TEST_INIT:
12677 info->name = "test_voicemail_msgcount";
12678 info->category = "/apps/app_voicemail/";
12679 info->summary = "Test Voicemail status checks";
12680 info->description =
12681 "Verify that message counts are correct when retrieved through the public API";
12682 return AST_TEST_NOT_RUN;
12683 case TEST_EXECUTE:
12684 break;
12685 }
12686
12687
12688 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12689 if ((syserr = ast_safe_system(syscmd))) {
12690 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12691 syserr > 0 ? strerror(syserr) : "unable to fork()");
12692 return AST_TEST_FAIL;
12693 }
12694
12695 #ifdef IMAP_STORAGE
12696 if (!(chan = ast_dummy_channel_alloc())) {
12697 ast_test_status_update(test, "Unable to create dummy channel\n");
12698 return AST_TEST_FAIL;
12699 }
12700 #endif
12701
12702 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12703 !(vmu = find_or_create(testcontext, testmailbox))) {
12704 ast_test_status_update(test, "Cannot create vmu structure\n");
12705 ast_unreplace_sigchld();
12706 #ifdef IMAP_STORAGE
12707 chan = ast_channel_unref(chan);
12708 #endif
12709 return AST_TEST_FAIL;
12710 }
12711
12712 populate_defaults(vmu);
12713 memset(&vms, 0, sizeof(vms));
12714
12715
12716 for (i = 0; i < 3; i++) {
12717 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12718 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12719 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12720
12721 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12722 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12723 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12724 if ((syserr = ast_safe_system(syscmd))) {
12725 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12726 syserr > 0 ? strerror(syserr) : "unable to fork()");
12727 ast_unreplace_sigchld();
12728 #ifdef IMAP_STORAGE
12729 chan = ast_channel_unref(chan);
12730 #endif
12731 return AST_TEST_FAIL;
12732 }
12733 }
12734
12735 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12736 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12737 fclose(txt);
12738 } else {
12739 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12740 res = AST_TEST_FAIL;
12741 break;
12742 }
12743 open_mailbox(&vms, vmu, folder2mbox[i]);
12744 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12745
12746
12747 for (j = 0; j < 3; j++) {
12748
12749 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12750 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12751 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12752 res = AST_TEST_FAIL;
12753 }
12754 }
12755
12756 new = old = urgent = 0;
12757 if (ast_app_inboxcount(testspec, &new, &old)) {
12758 ast_test_status_update(test, "inboxcount returned failure\n");
12759 res = AST_TEST_FAIL;
12760 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12761 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12762 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12763 res = AST_TEST_FAIL;
12764 }
12765
12766 new = old = urgent = 0;
12767 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12768 ast_test_status_update(test, "inboxcount2 returned failure\n");
12769 res = AST_TEST_FAIL;
12770 } else if (old != expected_results[i][6 + 0] ||
12771 urgent != expected_results[i][6 + 1] ||
12772 new != expected_results[i][6 + 2] ) {
12773 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12774 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12775 res = AST_TEST_FAIL;
12776 }
12777
12778 new = old = urgent = 0;
12779 for (j = 0; j < 3; j++) {
12780 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12781 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12782 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12783 res = AST_TEST_FAIL;
12784 }
12785 }
12786 }
12787
12788 for (i = 0; i < 3; i++) {
12789
12790
12791
12792 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12793 DISPOSE(tmp[i].dir, 0);
12794 }
12795
12796 if (vms.deleted) {
12797 ast_free(vms.deleted);
12798 }
12799 if (vms.heard) {
12800 ast_free(vms.heard);
12801 }
12802
12803 #ifdef IMAP_STORAGE
12804 chan = ast_channel_unref(chan);
12805 #endif
12806
12807
12808 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12809 if ((syserr = ast_safe_system(syscmd))) {
12810 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12811 syserr > 0 ? strerror(syserr) : "unable to fork()");
12812 }
12813
12814 return res;
12815 }
12816
12817 AST_TEST_DEFINE(test_voicemail_notify_endl)
12818 {
12819 int res = AST_TEST_PASS;
12820 char testcontext[] = "test";
12821 char testmailbox[] = "00000000";
12822 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12823 char attach[256], attach2[256];
12824 char buf[256] = "";
12825 struct ast_channel *chan = NULL;
12826 struct ast_vm_user *vmu, vmus = {
12827 .flags = 0,
12828 };
12829 FILE *file;
12830 struct {
12831 char *name;
12832 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12833 void *location;
12834 union {
12835 int intval;
12836 char *strval;
12837 } u;
12838 } test_items[] = {
12839 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12840 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12841 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12842 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12843 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12844 { "attach2", STRPTR, attach2, .u.strval = "" },
12845 { "attach", STRPTR, attach, .u.strval = "" },
12846 };
12847 int which;
12848
12849 switch (cmd) {
12850 case TEST_INIT:
12851 info->name = "test_voicemail_notify_endl";
12852 info->category = "/apps/app_voicemail/";
12853 info->summary = "Test Voicemail notification end-of-line";
12854 info->description =
12855 "Verify that notification emails use a consistent end-of-line character";
12856 return AST_TEST_NOT_RUN;
12857 case TEST_EXECUTE:
12858 break;
12859 }
12860
12861 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12862 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12863
12864 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12865 !(vmu = find_or_create(testcontext, testmailbox))) {
12866 ast_test_status_update(test, "Cannot create vmu structure\n");
12867 return AST_TEST_NOT_RUN;
12868 }
12869
12870 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12871 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12872 return AST_TEST_NOT_RUN;
12873 }
12874
12875 populate_defaults(vmu);
12876 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12877 #ifdef IMAP_STORAGE
12878
12879 #endif
12880
12881 file = tmpfile();
12882 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12883
12884 rewind(file);
12885 if (ftruncate(fileno(file), 0)) {
12886 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12887 res = AST_TEST_FAIL;
12888 break;
12889 }
12890
12891
12892 if (test_items[which].type == INT) {
12893 *((int *) test_items[which].location) = test_items[which].u.intval;
12894 } else if (test_items[which].type == FLAGVAL) {
12895 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12896 ast_clear_flag(vmu, test_items[which].u.intval);
12897 } else {
12898 ast_set_flag(vmu, test_items[which].u.intval);
12899 }
12900 } else if (test_items[which].type == STATIC) {
12901 strcpy(test_items[which].location, test_items[which].u.strval);
12902 } else if (test_items[which].type == STRPTR) {
12903 test_items[which].location = test_items[which].u.strval;
12904 }
12905
12906 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12907 rewind(file);
12908 while (fgets(buf, sizeof(buf), file)) {
12909 if (
12910 #ifdef IMAP_STORAGE
12911 buf[strlen(buf) - 2] != '\r'
12912 #else
12913 buf[strlen(buf) - 2] == '\r'
12914 #endif
12915 || buf[strlen(buf) - 1] != '\n') {
12916 res = AST_TEST_FAIL;
12917 }
12918 }
12919 }
12920 fclose(file);
12921 return res;
12922 }
12923
12924 AST_TEST_DEFINE(test_voicemail_load_config)
12925 {
12926 int res = AST_TEST_PASS;
12927 struct ast_vm_user *vmu;
12928 struct ast_config *cfg;
12929 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
12930 int fd;
12931 FILE *file;
12932 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
12933
12934 switch (cmd) {
12935 case TEST_INIT:
12936 info->name = "test_voicemail_load_config";
12937 info->category = "/apps/app_voicemail/";
12938 info->summary = "Test loading Voicemail config";
12939 info->description =
12940 "Verify that configuration is loaded consistently. "
12941 "This is to test regressions of ASTERISK-18838 where it was noticed that "
12942 "some options were loaded after the mailboxes were instantiated, causing "
12943 "those options not to be set correctly.";
12944 return AST_TEST_NOT_RUN;
12945 case TEST_EXECUTE:
12946 break;
12947 }
12948
12949
12950 if ((fd = mkstemp(config_filename)) < 0) {
12951 return AST_TEST_FAIL;
12952 }
12953 if (!(file = fdopen(fd, "w"))) {
12954 close(fd);
12955 unlink(config_filename);
12956 return AST_TEST_FAIL;
12957 }
12958 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
12959 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
12960 fputs("00000002 => 9999,Mrs. Test\n", file);
12961 fclose(file);
12962
12963 if (!(cfg = ast_config_load(config_filename, config_flags))) {
12964 res = AST_TEST_FAIL;
12965 goto cleanup;
12966 }
12967
12968 load_config_from_memory(1, cfg, NULL);
12969 ast_config_destroy(cfg);
12970
12971 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
12972 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
12973 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
12974
12975 AST_LIST_LOCK(&users);
12976 AST_LIST_TRAVERSE(&users, vmu, list) {
12977 if (!strcmp(vmu->mailbox, "00000001")) {
12978 if (0);
12979 CHECK(vmu, callback, "othercontext")
12980 CHECK(vmu, locale, "nl_NL.UTF-8")
12981 CHECK(vmu, zonetag, "central")
12982 } else if (!strcmp(vmu->mailbox, "00000002")) {
12983 if (0);
12984 CHECK(vmu, callback, "somecontext")
12985 CHECK(vmu, locale, "de_DE.UTF-8")
12986 CHECK(vmu, zonetag, "european")
12987 }
12988 }
12989 AST_LIST_UNLOCK(&users);
12990
12991 #undef CHECK
12992
12993
12994 load_config(1);
12995
12996 cleanup:
12997 unlink(config_filename);
12998 return res;
12999 }
13000
13001 #endif
13002
13003 static int reload(void)
13004 {
13005 return load_config(1);
13006 }
13007
13008 static int unload_module(void)
13009 {
13010 int res;
13011
13012 res = ast_unregister_application(app);
13013 res |= ast_unregister_application(app2);
13014 res |= ast_unregister_application(app3);
13015 res |= ast_unregister_application(app4);
13016 res |= ast_unregister_application(sayname_app);
13017 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13018 res |= ast_manager_unregister("VoicemailUsersList");
13019 res |= ast_data_unregister(NULL);
13020 #ifdef TEST_FRAMEWORK
13021 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13022 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13023 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13024 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13025 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13026 #endif
13027 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13028 ast_uninstall_vm_functions();
13029 ao2_ref(inprocess_container, -1);
13030
13031 if (poll_thread != AST_PTHREADT_NULL)
13032 stop_poll_thread();
13033
13034 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13035 ast_unload_realtime("voicemail");
13036 ast_unload_realtime("voicemail_data");
13037
13038 free_vm_users();
13039 free_vm_zones();
13040 return res;
13041 }
13042
13043 static int load_module(void)
13044 {
13045 int res;
13046 my_umask = umask(0);
13047 umask(my_umask);
13048
13049 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13050 return AST_MODULE_LOAD_DECLINE;
13051 }
13052
13053
13054 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13055
13056 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13057 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13058 }
13059
13060 if ((res = load_config(0)))
13061 return res;
13062
13063 res = ast_register_application_xml(app, vm_exec);
13064 res |= ast_register_application_xml(app2, vm_execmain);
13065 res |= ast_register_application_xml(app3, vm_box_exists);
13066 res |= ast_register_application_xml(app4, vmauthenticate);
13067 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13068 res |= ast_custom_function_register(&mailbox_exists_acf);
13069 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13070 #ifdef TEST_FRAMEWORK
13071 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13072 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13073 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13074 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13075 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13076 #endif
13077
13078 if (res)
13079 return res;
13080
13081 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13082 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13083
13084 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13085 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13086 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13087
13088 return res;
13089 }
13090
13091 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13092 {
13093 int cmd = 0;
13094 char destination[80] = "";
13095 int retries = 0;
13096
13097 if (!num) {
13098 ast_verb(3, "Destination number will be entered manually\n");
13099 while (retries < 3 && cmd != 't') {
13100 destination[1] = '\0';
13101 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13102 if (!cmd)
13103 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13104 if (!cmd)
13105 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13106 if (!cmd) {
13107 cmd = ast_waitfordigit(chan, 6000);
13108 if (cmd)
13109 destination[0] = cmd;
13110 }
13111 if (!cmd) {
13112 retries++;
13113 } else {
13114
13115 if (cmd < 0)
13116 return 0;
13117 if (cmd == '*') {
13118 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13119 return 0;
13120 }
13121 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13122 retries++;
13123 else
13124 cmd = 't';
13125 }
13126 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13127 }
13128 if (retries >= 3) {
13129 return 0;
13130 }
13131
13132 } else {
13133 if (option_verbose > 2)
13134 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13135 ast_copy_string(destination, num, sizeof(destination));
13136 }
13137
13138 if (!ast_strlen_zero(destination)) {
13139 if (destination[strlen(destination) -1 ] == '*')
13140 return 0;
13141 if (option_verbose > 2)
13142 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13143 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13144 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13145 chan->priority = 0;
13146 return 9;
13147 }
13148 return 0;
13149 }
13150
13151
13152
13153
13154
13155
13156
13157
13158
13159
13160
13161
13162
13163
13164 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)
13165 {
13166 int res = 0;
13167 char filename[PATH_MAX];
13168 struct ast_config *msg_cfg = NULL;
13169 const char *origtime, *context;
13170 char *name, *num;
13171 int retries = 0;
13172 char *cid;
13173 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13174
13175 vms->starting = 0;
13176
13177 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13178
13179
13180 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13181 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13182 msg_cfg = ast_config_load(filename, config_flags);
13183 DISPOSE(vms->curdir, vms->curmsg);
13184 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13185 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13186 return 0;
13187 }
13188
13189 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13190 ast_config_destroy(msg_cfg);
13191 return 0;
13192 }
13193
13194 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13195
13196 context = ast_variable_retrieve(msg_cfg, "message", "context");
13197 if (!strncasecmp("macro", context, 5))
13198 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13199 switch (option) {
13200 case 3:
13201 if (!res)
13202 res = play_message_datetime(chan, vmu, origtime, filename);
13203 if (!res)
13204 res = play_message_callerid(chan, vms, cid, context, 0);
13205
13206 res = 't';
13207 break;
13208
13209 case 2:
13210
13211 if (ast_strlen_zero(cid))
13212 break;
13213
13214 ast_callerid_parse(cid, &name, &num);
13215 while ((res > -1) && (res != 't')) {
13216 switch (res) {
13217 case '1':
13218 if (num) {
13219
13220 res = dialout(chan, vmu, num, vmu->callback);
13221 if (res) {
13222 ast_config_destroy(msg_cfg);
13223 return 9;
13224 }
13225 } else {
13226 res = '2';
13227 }
13228 break;
13229
13230 case '2':
13231
13232 if (!ast_strlen_zero(vmu->dialout)) {
13233 res = dialout(chan, vmu, NULL, vmu->dialout);
13234 if (res) {
13235 ast_config_destroy(msg_cfg);
13236 return 9;
13237 }
13238 } else {
13239 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13240 res = ast_play_and_wait(chan, "vm-sorry");
13241 }
13242 ast_config_destroy(msg_cfg);
13243 return res;
13244 case '*':
13245 res = 't';
13246 break;
13247 case '3':
13248 case '4':
13249 case '5':
13250 case '6':
13251 case '7':
13252 case '8':
13253 case '9':
13254 case '0':
13255
13256 res = ast_play_and_wait(chan, "vm-sorry");
13257 retries++;
13258 break;
13259 default:
13260 if (num) {
13261 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13262 res = ast_play_and_wait(chan, "vm-num-i-have");
13263 if (!res)
13264 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13265 if (!res)
13266 res = ast_play_and_wait(chan, "vm-tocallnum");
13267
13268 if (!ast_strlen_zero(vmu->dialout)) {
13269 if (!res)
13270 res = ast_play_and_wait(chan, "vm-calldiffnum");
13271 }
13272 } else {
13273 res = ast_play_and_wait(chan, "vm-nonumber");
13274 if (!ast_strlen_zero(vmu->dialout)) {
13275 if (!res)
13276 res = ast_play_and_wait(chan, "vm-toenternumber");
13277 }
13278 }
13279 if (!res) {
13280 res = ast_play_and_wait(chan, "vm-star-cancel");
13281 }
13282 if (!res) {
13283 res = ast_waitfordigit(chan, 6000);
13284 }
13285 if (!res) {
13286 retries++;
13287 if (retries > 3) {
13288 res = 't';
13289 }
13290 }
13291 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13292 break;
13293
13294 }
13295 if (res == 't')
13296 res = 0;
13297 else if (res == '*')
13298 res = -1;
13299 }
13300 break;
13301
13302 case 1:
13303
13304 if (ast_strlen_zero(cid))
13305 break;
13306
13307 ast_callerid_parse(cid, &name, &num);
13308 if (!num) {
13309 ast_verb(3, "No CID number available, no reply sent\n");
13310 if (!res)
13311 res = ast_play_and_wait(chan, "vm-nonumber");
13312 ast_config_destroy(msg_cfg);
13313 return res;
13314 } else {
13315 struct ast_vm_user vmu2;
13316 if (find_user(&vmu2, vmu->context, num)) {
13317 struct leave_vm_options leave_options;
13318 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13319 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13320
13321 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13322
13323 memset(&leave_options, 0, sizeof(leave_options));
13324 leave_options.record_gain = record_gain;
13325 res = leave_voicemail(chan, mailbox, &leave_options);
13326 if (!res)
13327 res = 't';
13328 ast_config_destroy(msg_cfg);
13329 return res;
13330 } else {
13331
13332 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13333 ast_play_and_wait(chan, "vm-nobox");
13334 res = 't';
13335 ast_config_destroy(msg_cfg);
13336 return res;
13337 }
13338 }
13339 res = 0;
13340
13341 break;
13342 }
13343
13344 #ifndef IMAP_STORAGE
13345 ast_config_destroy(msg_cfg);
13346
13347 if (!res) {
13348 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13349 vms->heard[msg] = 1;
13350 res = wait_file(chan, vms, vms->fn);
13351 }
13352 #endif
13353 return res;
13354 }
13355
13356 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13357 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13358 signed char record_gain, struct vm_state *vms, char *flag)
13359 {
13360
13361 int res = 0;
13362 int cmd = 0;
13363 int max_attempts = 3;
13364 int attempts = 0;
13365 int recorded = 0;
13366 int msg_exists = 0;
13367 signed char zero_gain = 0;
13368 char tempfile[PATH_MAX];
13369 char *acceptdtmf = "#";
13370 char *canceldtmf = "";
13371 int canceleddtmf = 0;
13372
13373
13374
13375
13376 if (duration == NULL) {
13377 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13378 return -1;
13379 }
13380
13381 if (!outsidecaller)
13382 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13383 else
13384 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13385
13386 cmd = '3';
13387
13388 while ((cmd >= 0) && (cmd != 't')) {
13389 switch (cmd) {
13390 case '1':
13391 if (!msg_exists) {
13392
13393 cmd = '3';
13394 break;
13395 } else {
13396
13397 ast_verb(3, "Saving message as is\n");
13398 if (!outsidecaller)
13399 ast_filerename(tempfile, recordfile, NULL);
13400 ast_stream_and_wait(chan, "vm-msgsaved", "");
13401 if (!outsidecaller) {
13402
13403 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13404 DISPOSE(recordfile, -1);
13405 }
13406 cmd = 't';
13407 return res;
13408 }
13409 case '2':
13410
13411 ast_verb(3, "Reviewing the message\n");
13412 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13413 break;
13414 case '3':
13415 msg_exists = 0;
13416
13417 if (recorded == 1)
13418 ast_verb(3, "Re-recording the message\n");
13419 else
13420 ast_verb(3, "Recording the message\n");
13421
13422 if (recorded && outsidecaller) {
13423 cmd = ast_play_and_wait(chan, INTRO);
13424 cmd = ast_play_and_wait(chan, "beep");
13425 }
13426 recorded = 1;
13427
13428 if (record_gain)
13429 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13430 if (ast_test_flag(vmu, VM_OPERATOR))
13431 canceldtmf = "0";
13432 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13433 if (strchr(canceldtmf, cmd)) {
13434
13435 canceleddtmf = 1;
13436 }
13437 if (record_gain)
13438 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13439 if (cmd == -1) {
13440
13441 if (!outsidecaller) {
13442
13443 ast_filedelete(tempfile, NULL);
13444 }
13445 return cmd;
13446 }
13447 if (cmd == '0') {
13448 break;
13449 } else if (cmd == '*') {
13450 break;
13451 #if 0
13452 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13453
13454 ast_verb(3, "Message too short\n");
13455 cmd = ast_play_and_wait(chan, "vm-tooshort");
13456 cmd = ast_filedelete(tempfile, NULL);
13457 break;
13458 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13459
13460 ast_verb(3, "Nothing recorded\n");
13461 cmd = ast_filedelete(tempfile, NULL);
13462 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13463 if (!cmd)
13464 cmd = ast_play_and_wait(chan, "vm-speakup");
13465 break;
13466 #endif
13467 } else {
13468
13469 msg_exists = 1;
13470 cmd = 0;
13471 }
13472 break;
13473 case '4':
13474 if (outsidecaller) {
13475
13476 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13477 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13478 res = ast_play_and_wait(chan, "vm-marked-urgent");
13479 strcpy(flag, "Urgent");
13480 } else if (flag) {
13481 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13482 res = ast_play_and_wait(chan, "vm-urgent-removed");
13483 strcpy(flag, "");
13484 } else {
13485 ast_play_and_wait(chan, "vm-sorry");
13486 }
13487 cmd = 0;
13488 } else {
13489 cmd = ast_play_and_wait(chan, "vm-sorry");
13490 }
13491 break;
13492 case '5':
13493 case '6':
13494 case '7':
13495 case '8':
13496 case '9':
13497 case '*':
13498 case '#':
13499 cmd = ast_play_and_wait(chan, "vm-sorry");
13500 break;
13501 #if 0
13502
13503
13504 case '*':
13505
13506 cmd = ast_play_and_wait(chan, "vm-deleted");
13507 cmd = ast_filedelete(tempfile, NULL);
13508 if (outsidecaller) {
13509 res = vm_exec(chan, NULL);
13510 return res;
13511 }
13512 else
13513 return 1;
13514 #endif
13515 case '0':
13516 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13517 cmd = ast_play_and_wait(chan, "vm-sorry");
13518 break;
13519 }
13520 if (msg_exists || recorded) {
13521 cmd = ast_play_and_wait(chan, "vm-saveoper");
13522 if (!cmd)
13523 cmd = ast_waitfordigit(chan, 3000);
13524 if (cmd == '1') {
13525 ast_filerename(tempfile, recordfile, NULL);
13526 ast_play_and_wait(chan, "vm-msgsaved");
13527 cmd = '0';
13528 } else if (cmd == '4') {
13529 if (flag) {
13530 ast_play_and_wait(chan, "vm-marked-urgent");
13531 strcpy(flag, "Urgent");
13532 }
13533 ast_play_and_wait(chan, "vm-msgsaved");
13534 cmd = '0';
13535 } else {
13536 ast_play_and_wait(chan, "vm-deleted");
13537 DELETE(tempfile, -1, tempfile, vmu);
13538 cmd = '0';
13539 }
13540 }
13541 return cmd;
13542 default:
13543
13544
13545
13546 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13547 return cmd;
13548 if (msg_exists) {
13549 cmd = ast_play_and_wait(chan, "vm-review");
13550 if (!cmd && outsidecaller) {
13551 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13552 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13553 } else if (flag) {
13554 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13555 }
13556 }
13557 } else {
13558 cmd = ast_play_and_wait(chan, "vm-torerecord");
13559 if (!cmd)
13560 cmd = ast_waitfordigit(chan, 600);
13561 }
13562
13563 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13564 cmd = ast_play_and_wait(chan, "vm-reachoper");
13565 if (!cmd)
13566 cmd = ast_waitfordigit(chan, 600);
13567 }
13568 #if 0
13569 if (!cmd)
13570 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13571 #endif
13572 if (!cmd)
13573 cmd = ast_waitfordigit(chan, 6000);
13574 if (!cmd) {
13575 attempts++;
13576 }
13577 if (attempts > max_attempts) {
13578 cmd = 't';
13579 }
13580 }
13581 }
13582 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13583
13584 ast_filedelete(tempfile, NULL);
13585 }
13586
13587 if (cmd != 't' && outsidecaller)
13588 ast_play_and_wait(chan, "vm-goodbye");
13589
13590 return cmd;
13591 }
13592
13593
13594
13595
13596
13597 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13598 .load = load_module,
13599 .unload = unload_module,
13600 .reload = reload,
13601 .nonoptreq = "res_adsi,res_smdi",
13602 );