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
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 #include "asterisk.h"
00074
00075 #ifdef IMAP_STORAGE
00076 #include <ctype.h>
00077 #include <signal.h>
00078 #include <pwd.h>
00079 #ifdef USE_SYSTEM_IMAP
00080 #include <imap/c-client.h>
00081 #include <imap/imap4r1.h>
00082 #include <imap/linkage.h>
00083 #elif defined (USE_SYSTEM_CCLIENT)
00084 #include <c-client/c-client.h>
00085 #include <c-client/imap4r1.h>
00086 #include <c-client/linkage.h>
00087 #else
00088 #include "c-client.h"
00089 #include "imap4r1.h"
00090 #include "linkage.h"
00091 #endif
00092 #endif
00093
00094 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 356797 $")
00095
00096 #include "asterisk/paths.h"
00097 #include <sys/time.h>
00098 #include <sys/stat.h>
00099 #include <sys/mman.h>
00100 #include <time.h>
00101 #include <dirent.h>
00102 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00103 #include <sys/wait.h>
00104 #endif
00105
00106 #include "asterisk/logger.h"
00107 #include "asterisk/lock.h"
00108 #include "asterisk/file.h"
00109 #include "asterisk/channel.h"
00110 #include "asterisk/pbx.h"
00111 #include "asterisk/config.h"
00112 #include "asterisk/say.h"
00113 #include "asterisk/module.h"
00114 #include "asterisk/adsi.h"
00115 #include "asterisk/app.h"
00116 #include "asterisk/manager.h"
00117 #include "asterisk/dsp.h"
00118 #include "asterisk/localtime.h"
00119 #include "asterisk/cli.h"
00120 #include "asterisk/utils.h"
00121 #include "asterisk/stringfields.h"
00122 #include "asterisk/smdi.h"
00123 #include "asterisk/astobj2.h"
00124 #include "asterisk/event.h"
00125 #include "asterisk/taskprocessor.h"
00126 #include "asterisk/test.h"
00127
00128 #ifdef ODBC_STORAGE
00129 #include "asterisk/res_odbc.h"
00130 #endif
00131
00132 #ifdef IMAP_STORAGE
00133 #include "asterisk/threadstorage.h"
00134 #endif
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
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 #ifdef IMAP_STORAGE
00375 static char imapserver[48];
00376 static char imapport[8];
00377 static char imapflags[128];
00378 static char imapfolder[64];
00379 static char imapparentfolder[64] = "\0";
00380 static char greetingfolder[64];
00381 static char authuser[32];
00382 static char authpassword[42];
00383 static int imapversion = 1;
00384
00385 static int expungeonhangup = 1;
00386 static int imapgreetings = 0;
00387 static char delimiter = '\0';
00388
00389 struct vm_state;
00390 struct ast_vm_user;
00391
00392 AST_THREADSTORAGE(ts_vmstate);
00393
00394
00395 static int init_mailstream(struct vm_state *vms, int box);
00396 static void write_file(char *filename, char *buffer, unsigned long len);
00397 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00398 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00399 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00400 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00401 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00402 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00403 static void vmstate_insert(struct vm_state *vms);
00404 static void vmstate_delete(struct vm_state *vms);
00405 static void set_update(MAILSTREAM * stream);
00406 static void init_vm_state(struct vm_state *vms);
00407 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00408 static void get_mailbox_delimiter(MAILSTREAM *stream);
00409 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00410 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00411 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);
00412 static void update_messages_by_imapuser(const char *user, unsigned long number);
00413 static int vm_delete(char *file);
00414
00415 static int imap_remove_file (char *dir, int msgnum);
00416 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00417 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00418 static void check_quota(struct vm_state *vms, char *mailbox);
00419 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00420 struct vmstate {
00421 struct vm_state *vms;
00422 AST_LIST_ENTRY(vmstate) list;
00423 };
00424
00425 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00426
00427 #endif
00428
00429 #define SMDI_MWI_WAIT_TIMEOUT 1000
00430
00431 #define COMMAND_TIMEOUT 5000
00432
00433 #define VOICEMAIL_DIR_MODE 0777
00434 #define VOICEMAIL_FILE_MODE 0666
00435 #define CHUNKSIZE 65536
00436
00437 #define VOICEMAIL_CONFIG "voicemail.conf"
00438 #define ASTERISK_USERNAME "asterisk"
00439
00440
00441
00442
00443 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00444 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00445 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00446 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00447 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00448 #define VALID_DTMF "1234567890*#"
00449
00450
00451
00452 #define SENDMAIL "/usr/sbin/sendmail -t"
00453
00454 #define INTRO "vm-intro"
00455
00456 #define MAXMSG 100
00457 #define MAXMSGLIMIT 9999
00458
00459 #define MINPASSWORD 0
00460
00461 #define BASELINELEN 72
00462 #define BASEMAXINLINE 256
00463 #ifdef IMAP_STORAGE
00464 #define ENDL "\r\n"
00465 #else
00466 #define ENDL "\n"
00467 #endif
00468
00469 #define MAX_DATETIME_FORMAT 512
00470 #define MAX_NUM_CID_CONTEXTS 10
00471
00472 #define VM_REVIEW (1 << 0)
00473 #define VM_OPERATOR (1 << 1)
00474 #define VM_SAYCID (1 << 2)
00475 #define VM_SVMAIL (1 << 3)
00476 #define VM_ENVELOPE (1 << 4)
00477 #define VM_SAYDURATION (1 << 5)
00478 #define VM_SKIPAFTERCMD (1 << 6)
00479 #define VM_FORCENAME (1 << 7)
00480 #define VM_FORCEGREET (1 << 8)
00481 #define VM_PBXSKIP (1 << 9)
00482 #define VM_DIRECFORWARD (1 << 10)
00483 #define VM_ATTACH (1 << 11)
00484 #define VM_DELETE (1 << 12)
00485 #define VM_ALLOCED (1 << 13)
00486 #define VM_SEARCH (1 << 14)
00487 #define VM_TEMPGREETWARN (1 << 15)
00488 #define VM_MOVEHEARD (1 << 16)
00489 #define VM_MESSAGEWRAP (1 << 17)
00490 #define VM_FWDURGAUTO (1 << 18)
00491 #define ERROR_LOCK_PATH -100
00492 #define OPERATOR_EXIT 300
00493
00494
00495 enum vm_box {
00496 NEW_FOLDER,
00497 OLD_FOLDER,
00498 WORK_FOLDER,
00499 FAMILY_FOLDER,
00500 FRIENDS_FOLDER,
00501 GREETINGS_FOLDER
00502 };
00503
00504 enum vm_option_flags {
00505 OPT_SILENT = (1 << 0),
00506 OPT_BUSY_GREETING = (1 << 1),
00507 OPT_UNAVAIL_GREETING = (1 << 2),
00508 OPT_RECORDGAIN = (1 << 3),
00509 OPT_PREPEND_MAILBOX = (1 << 4),
00510 OPT_AUTOPLAY = (1 << 6),
00511 OPT_DTMFEXIT = (1 << 7),
00512 OPT_MESSAGE_Urgent = (1 << 8),
00513 OPT_MESSAGE_PRIORITY = (1 << 9)
00514 };
00515
00516 enum vm_option_args {
00517 OPT_ARG_RECORDGAIN = 0,
00518 OPT_ARG_PLAYFOLDER = 1,
00519 OPT_ARG_DTMFEXIT = 2,
00520
00521 OPT_ARG_ARRAY_SIZE = 3,
00522 };
00523
00524 enum vm_passwordlocation {
00525 OPT_PWLOC_VOICEMAILCONF = 0,
00526 OPT_PWLOC_SPOOLDIR = 1,
00527 OPT_PWLOC_USERSCONF = 2,
00528 };
00529
00530 AST_APP_OPTIONS(vm_app_options, {
00531 AST_APP_OPTION('s', OPT_SILENT),
00532 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00533 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00534 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00535 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00536 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00537 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00538 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00539 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00540 });
00541
00542 static int load_config(int reload);
00543 #ifdef TEST_FRAMEWORK
00544 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00545 #endif
00546 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
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
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 struct baseio {
00632 int iocp;
00633 int iolen;
00634 int linelength;
00635 int ateof;
00636 unsigned char iobuf[BASEMAXINLINE];
00637 };
00638
00639
00640
00641 struct ast_vm_user {
00642 char context[AST_MAX_CONTEXT];
00643 char mailbox[AST_MAX_EXTENSION];
00644 char password[80];
00645 char fullname[80];
00646 char email[80];
00647 char *emailsubject;
00648 char *emailbody;
00649 char pager[80];
00650 char serveremail[80];
00651 char mailcmd[160];
00652 char language[MAX_LANGUAGE];
00653 char zonetag[80];
00654 char locale[20];
00655 char callback[80];
00656 char dialout[80];
00657 char uniqueid[80];
00658 char exit[80];
00659 char attachfmt[20];
00660 unsigned int flags;
00661 int saydurationm;
00662 int minsecs;
00663 int maxmsg;
00664 int maxdeletedmsg;
00665 int maxsecs;
00666 int passwordlocation;
00667 #ifdef IMAP_STORAGE
00668 char imapuser[80];
00669 char imappassword[80];
00670 char imapfolder[64];
00671 char imapvmshareid[80];
00672 int imapversion;
00673 #endif
00674 double volgain;
00675 AST_LIST_ENTRY(ast_vm_user) list;
00676 };
00677
00678
00679 struct vm_zone {
00680 AST_LIST_ENTRY(vm_zone) list;
00681 char name[80];
00682 char timezone[80];
00683 char msg_format[512];
00684 };
00685
00686 #define VMSTATE_MAX_MSG_ARRAY 256
00687
00688
00689 struct vm_state {
00690 char curbox[80];
00691 char username[80];
00692 char context[80];
00693 char curdir[PATH_MAX];
00694 char vmbox[PATH_MAX];
00695 char fn[PATH_MAX];
00696 char intro[PATH_MAX];
00697 int *deleted;
00698 int *heard;
00699 int dh_arraysize;
00700 int curmsg;
00701 int lastmsg;
00702 int newmessages;
00703 int oldmessages;
00704 int urgentmessages;
00705 int starting;
00706 int repeats;
00707 #ifdef IMAP_STORAGE
00708 ast_mutex_t lock;
00709 int updated;
00710 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00711 MAILSTREAM *mailstream;
00712 int vmArrayIndex;
00713 char imapuser[80];
00714 char imapfolder[64];
00715 int imapversion;
00716 int interactive;
00717 char introfn[PATH_MAX];
00718 unsigned int quota_limit;
00719 unsigned int quota_usage;
00720 struct vm_state *persist_vms;
00721 #endif
00722 };
00723
00724 #ifdef ODBC_STORAGE
00725 static char odbc_database[80];
00726 static char odbc_table[80];
00727 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00728 #define DISPOSE(a,b) remove_file(a,b)
00729 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00730 #define EXISTS(a,b,c,d) (message_exists(a,b))
00731 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00732 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00733 #define DELETE(a,b,c,d) (delete_file(a,b))
00734 #else
00735 #ifdef IMAP_STORAGE
00736 #define DISPOSE(a,b) (imap_remove_file(a,b))
00737 #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))
00738 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00739 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00740 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00741 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00742 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00743 #else
00744 #define RETRIEVE(a,b,c,d)
00745 #define DISPOSE(a,b)
00746 #define STORE(a,b,c,d,e,f,g,h,i,j)
00747 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00748 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00749 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00750 #define DELETE(a,b,c,d) (vm_delete(c))
00751 #endif
00752 #endif
00753
00754 static char VM_SPOOL_DIR[PATH_MAX];
00755
00756 static char ext_pass_cmd[128];
00757 static char ext_pass_check_cmd[128];
00758
00759 static int my_umask;
00760
00761 #define PWDCHANGE_INTERNAL (1 << 1)
00762 #define PWDCHANGE_EXTERNAL (1 << 2)
00763 static int pwdchange = PWDCHANGE_INTERNAL;
00764
00765 #ifdef ODBC_STORAGE
00766 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00767 #else
00768 # ifdef IMAP_STORAGE
00769 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00770 # else
00771 # define tdesc "Comedian Mail (Voicemail System)"
00772 # endif
00773 #endif
00774
00775 static char userscontext[AST_MAX_EXTENSION] = "default";
00776
00777 static char *addesc = "Comedian Mail";
00778
00779
00780 static char *app = "VoiceMail";
00781
00782
00783 static char *app2 = "VoiceMailMain";
00784
00785 static char *app3 = "MailboxExists";
00786 static char *app4 = "VMAuthenticate";
00787
00788 static char *sayname_app = "VMSayName";
00789
00790 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00791 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00792 static char zonetag[80];
00793 static char locale[20];
00794 static int maxsilence;
00795 static int maxmsg;
00796 static int maxdeletedmsg;
00797 static int silencethreshold = 128;
00798 static char serveremail[80];
00799 static char mailcmd[160];
00800 static char externnotify[160];
00801 static struct ast_smdi_interface *smdi_iface = NULL;
00802 static char vmfmts[80];
00803 static double volgain;
00804 static int vmminsecs;
00805 static int vmmaxsecs;
00806 static int maxgreet;
00807 static int skipms;
00808 static int maxlogins;
00809 static int minpassword;
00810 static int passwordlocation;
00811
00812
00813
00814 static unsigned int poll_mailboxes;
00815
00816
00817 static unsigned int poll_freq;
00818
00819 #define DEFAULT_POLL_FREQ 30
00820
00821 AST_MUTEX_DEFINE_STATIC(poll_lock);
00822 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00823 static pthread_t poll_thread = AST_PTHREADT_NULL;
00824 static unsigned char poll_thread_run;
00825
00826
00827 static struct ast_event_sub *mwi_sub_sub;
00828
00829 static struct ast_event_sub *mwi_unsub_sub;
00830
00831
00832
00833
00834
00835
00836
00837
00838 struct mwi_sub {
00839 AST_RWLIST_ENTRY(mwi_sub) entry;
00840 int old_urgent;
00841 int old_new;
00842 int old_old;
00843 uint32_t uniqueid;
00844 char mailbox[1];
00845 };
00846
00847 struct mwi_sub_task {
00848 const char *mailbox;
00849 const char *context;
00850 uint32_t uniqueid;
00851 };
00852
00853 static struct ast_taskprocessor *mwi_subscription_tps;
00854
00855 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00856
00857
00858 static char listen_control_forward_key[12];
00859 static char listen_control_reverse_key[12];
00860 static char listen_control_pause_key[12];
00861 static char listen_control_restart_key[12];
00862 static char listen_control_stop_key[12];
00863
00864
00865 static char vm_password[80] = "vm-password";
00866 static char vm_newpassword[80] = "vm-newpassword";
00867 static char vm_passchanged[80] = "vm-passchanged";
00868 static char vm_reenterpassword[80] = "vm-reenterpassword";
00869 static char vm_mismatch[80] = "vm-mismatch";
00870 static char vm_invalid_password[80] = "vm-invalid-password";
00871 static char vm_pls_try_again[80] = "vm-pls-try-again";
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883 static char vm_prepend_timeout[80] = "vm-then-pound";
00884
00885 static struct ast_flags globalflags = {0};
00886
00887 static int saydurationminfo;
00888
00889 static char dialcontext[AST_MAX_CONTEXT] = "";
00890 static char callcontext[AST_MAX_CONTEXT] = "";
00891 static char exitcontext[AST_MAX_CONTEXT] = "";
00892
00893 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00894
00895
00896 static char *emailbody = NULL;
00897 static char *emailsubject = NULL;
00898 static char *pagerbody = NULL;
00899 static char *pagersubject = NULL;
00900 static char fromstring[100];
00901 static char pagerfromstring[100];
00902 static char charset[32] = "ISO-8859-1";
00903
00904 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00905 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00906 static int adsiver = 1;
00907 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00908 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00909
00910
00911 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00912 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);
00913 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00914 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00915 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00916 signed char record_gain, struct vm_state *vms, char *flag);
00917 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00918 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00919 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);
00920 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);
00921 static void apply_options(struct ast_vm_user *vmu, const char *options);
00922 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);
00923 static int is_valid_dtmf(const char *key);
00924 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00925 static int write_password_to_file(const char *secretfn, const char *password);
00926 static const char *substitute_escapes(const char *value);
00927 static void free_user(struct ast_vm_user *vmu);
00928
00929 struct ao2_container *inprocess_container;
00930
00931 struct inprocess {
00932 int count;
00933 char *context;
00934 char mailbox[0];
00935 };
00936
00937 static int inprocess_hash_fn(const void *obj, const int flags)
00938 {
00939 const struct inprocess *i = obj;
00940 return atoi(i->mailbox);
00941 }
00942
00943 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00944 {
00945 struct inprocess *i = obj, *j = arg;
00946 if (strcmp(i->mailbox, j->mailbox)) {
00947 return 0;
00948 }
00949 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00950 }
00951
00952 static int inprocess_count(const char *context, const char *mailbox, int delta)
00953 {
00954 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00955 arg->context = arg->mailbox + strlen(mailbox) + 1;
00956 strcpy(arg->mailbox, mailbox);
00957 strcpy(arg->context, context);
00958 ao2_lock(inprocess_container);
00959 if ((i = ao2_find(inprocess_container, arg, 0))) {
00960 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00961 ao2_unlock(inprocess_container);
00962 ao2_ref(i, -1);
00963 return ret;
00964 }
00965 if (delta < 0) {
00966 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00967 }
00968 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00969 ao2_unlock(inprocess_container);
00970 return 0;
00971 }
00972 i->context = i->mailbox + strlen(mailbox) + 1;
00973 strcpy(i->mailbox, mailbox);
00974 strcpy(i->context, context);
00975 i->count = delta;
00976 ao2_link(inprocess_container, i);
00977 ao2_unlock(inprocess_container);
00978 ao2_ref(i, -1);
00979 return 0;
00980 }
00981
00982 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00983 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00984 #endif
00985
00986
00987
00988
00989
00990
00991
00992 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00993 {
00994 char *bufptr = buf;
00995 for (; *input; input++) {
00996 if (*input < 32) {
00997 continue;
00998 }
00999 *bufptr++ = *input;
01000 if (bufptr == buf + buflen - 1) {
01001 break;
01002 }
01003 }
01004 *bufptr = '\0';
01005 return buf;
01006 }
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022 static void populate_defaults(struct ast_vm_user *vmu)
01023 {
01024 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01025 vmu->passwordlocation = passwordlocation;
01026 if (saydurationminfo) {
01027 vmu->saydurationm = saydurationminfo;
01028 }
01029 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01030 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01031 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01032 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01033 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01034 if (vmminsecs) {
01035 vmu->minsecs = vmminsecs;
01036 }
01037 if (vmmaxsecs) {
01038 vmu->maxsecs = vmmaxsecs;
01039 }
01040 if (maxmsg) {
01041 vmu->maxmsg = maxmsg;
01042 }
01043 if (maxdeletedmsg) {
01044 vmu->maxdeletedmsg = maxdeletedmsg;
01045 }
01046 vmu->volgain = volgain;
01047 ast_free(vmu->emailsubject);
01048 vmu->emailsubject = NULL;
01049 ast_free(vmu->emailbody);
01050 vmu->emailbody = NULL;
01051 #ifdef IMAP_STORAGE
01052 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01053 #endif
01054 }
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01065 {
01066 int x;
01067 if (!strcasecmp(var, "attach")) {
01068 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01069 } else if (!strcasecmp(var, "attachfmt")) {
01070 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01071 } else if (!strcasecmp(var, "serveremail")) {
01072 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01073 } else if (!strcasecmp(var, "emailbody")) {
01074 vmu->emailbody = ast_strdup(substitute_escapes(value));
01075 } else if (!strcasecmp(var, "emailsubject")) {
01076 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01077 } else if (!strcasecmp(var, "language")) {
01078 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01079 } else if (!strcasecmp(var, "tz")) {
01080 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01081 } else if (!strcasecmp(var, "locale")) {
01082 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01083 #ifdef IMAP_STORAGE
01084 } else if (!strcasecmp(var, "imapuser")) {
01085 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01086 vmu->imapversion = imapversion;
01087 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01088 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01089 vmu->imapversion = imapversion;
01090 } else if (!strcasecmp(var, "imapfolder")) {
01091 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01092 } else if (!strcasecmp(var, "imapvmshareid")) {
01093 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01094 vmu->imapversion = imapversion;
01095 #endif
01096 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01097 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01098 } else if (!strcasecmp(var, "saycid")){
01099 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01100 } else if (!strcasecmp(var, "sendvoicemail")){
01101 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01102 } else if (!strcasecmp(var, "review")){
01103 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01104 } else if (!strcasecmp(var, "tempgreetwarn")){
01105 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01106 } else if (!strcasecmp(var, "messagewrap")){
01107 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01108 } else if (!strcasecmp(var, "operator")) {
01109 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01110 } else if (!strcasecmp(var, "envelope")){
01111 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01112 } else if (!strcasecmp(var, "moveheard")){
01113 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01114 } else if (!strcasecmp(var, "sayduration")){
01115 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01116 } else if (!strcasecmp(var, "saydurationm")){
01117 if (sscanf(value, "%30d", &x) == 1) {
01118 vmu->saydurationm = x;
01119 } else {
01120 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01121 }
01122 } else if (!strcasecmp(var, "forcename")){
01123 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01124 } else if (!strcasecmp(var, "forcegreetings")){
01125 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01126 } else if (!strcasecmp(var, "callback")) {
01127 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01128 } else if (!strcasecmp(var, "dialout")) {
01129 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01130 } else if (!strcasecmp(var, "exitcontext")) {
01131 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01132 } else if (!strcasecmp(var, "minsecs")) {
01133 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01134 vmu->minsecs = x;
01135 } else {
01136 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01137 vmu->minsecs = vmminsecs;
01138 }
01139 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01140 vmu->maxsecs = atoi(value);
01141 if (vmu->maxsecs <= 0) {
01142 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01143 vmu->maxsecs = vmmaxsecs;
01144 } else {
01145 vmu->maxsecs = atoi(value);
01146 }
01147 if (!strcasecmp(var, "maxmessage"))
01148 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01149 } else if (!strcasecmp(var, "maxmsg")) {
01150 vmu->maxmsg = atoi(value);
01151
01152 if (vmu->maxmsg < 0) {
01153 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01154 vmu->maxmsg = MAXMSG;
01155 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01156 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01157 vmu->maxmsg = MAXMSGLIMIT;
01158 }
01159 } else if (!strcasecmp(var, "nextaftercmd")) {
01160 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01161 } else if (!strcasecmp(var, "backupdeleted")) {
01162 if (sscanf(value, "%30d", &x) == 1)
01163 vmu->maxdeletedmsg = x;
01164 else if (ast_true(value))
01165 vmu->maxdeletedmsg = MAXMSG;
01166 else
01167 vmu->maxdeletedmsg = 0;
01168
01169 if (vmu->maxdeletedmsg < 0) {
01170 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01171 vmu->maxdeletedmsg = MAXMSG;
01172 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01173 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01174 vmu->maxdeletedmsg = MAXMSGLIMIT;
01175 }
01176 } else if (!strcasecmp(var, "volgain")) {
01177 sscanf(value, "%30lf", &vmu->volgain);
01178 } else if (!strcasecmp(var, "passwordlocation")) {
01179 if (!strcasecmp(value, "spooldir")) {
01180 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01181 } else {
01182 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01183 }
01184 } else if (!strcasecmp(var, "options")) {
01185 apply_options(vmu, value);
01186 }
01187 }
01188
01189 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01190 {
01191 int fds[2], pid = 0;
01192
01193 memset(buf, 0, len);
01194
01195 if (pipe(fds)) {
01196 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01197 } else {
01198
01199 pid = ast_safe_fork(0);
01200
01201 if (pid < 0) {
01202
01203 close(fds[0]);
01204 close(fds[1]);
01205 snprintf(buf, len, "FAILURE: Fork failed");
01206 } else if (pid) {
01207
01208 close(fds[1]);
01209 if (read(fds[0], buf, len) < 0) {
01210 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01211 }
01212 close(fds[0]);
01213 } else {
01214
01215 AST_DECLARE_APP_ARGS(arg,
01216 AST_APP_ARG(v)[20];
01217 );
01218 char *mycmd = ast_strdupa(command);
01219
01220 close(fds[0]);
01221 dup2(fds[1], STDOUT_FILENO);
01222 close(fds[1]);
01223 ast_close_fds_above_n(STDOUT_FILENO);
01224
01225 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01226
01227 execv(arg.v[0], arg.v);
01228 printf("FAILURE: %s", strerror(errno));
01229 _exit(0);
01230 }
01231 }
01232 return buf;
01233 }
01234
01235
01236
01237
01238
01239
01240
01241
01242 static int check_password(struct ast_vm_user *vmu, char *password)
01243 {
01244
01245 if (strlen(password) < minpassword)
01246 return 1;
01247
01248 if (!ast_strlen_zero(password) && password[0] == '*')
01249 return 1;
01250 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01251 char cmd[255], buf[255];
01252
01253 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01254
01255 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01256 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01257 ast_debug(5, "Result: %s\n", buf);
01258 if (!strncasecmp(buf, "VALID", 5)) {
01259 ast_debug(3, "Passed password check: '%s'\n", buf);
01260 return 0;
01261 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01262 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01263 return 0;
01264 } else {
01265 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01266 return 1;
01267 }
01268 }
01269 }
01270 return 0;
01271 }
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01284 {
01285 int res = -1;
01286 if (!strcmp(vmu->password, password)) {
01287
01288 return 0;
01289 }
01290
01291 if (strlen(password) > 10) {
01292 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01293 }
01294 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01295 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01296 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01297 res = 0;
01298 }
01299 return res;
01300 }
01301
01302
01303
01304
01305 static void apply_options(struct ast_vm_user *vmu, const char *options)
01306 {
01307 char *stringp;
01308 char *s;
01309 char *var, *value;
01310 stringp = ast_strdupa(options);
01311 while ((s = strsep(&stringp, "|"))) {
01312 value = s;
01313 if ((var = strsep(&value, "=")) && value) {
01314 apply_option(vmu, var, value);
01315 }
01316 }
01317 }
01318
01319
01320
01321
01322
01323
01324 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01325 {
01326 for (; var; var = var->next) {
01327 if (!strcasecmp(var->name, "vmsecret")) {
01328 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01329 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01330 if (ast_strlen_zero(retval->password)) {
01331 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01332 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01333 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01334 } else {
01335 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01336 }
01337 }
01338 } else if (!strcasecmp(var->name, "uniqueid")) {
01339 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01340 } else if (!strcasecmp(var->name, "pager")) {
01341 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01342 } else if (!strcasecmp(var->name, "email")) {
01343 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01344 } else if (!strcasecmp(var->name, "fullname")) {
01345 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01346 } else if (!strcasecmp(var->name, "context")) {
01347 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01348 } else if (!strcasecmp(var->name, "emailsubject")) {
01349 ast_free(retval->emailsubject);
01350 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01351 } else if (!strcasecmp(var->name, "emailbody")) {
01352 ast_free(retval->emailbody);
01353 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01354 #ifdef IMAP_STORAGE
01355 } else if (!strcasecmp(var->name, "imapuser")) {
01356 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01357 retval->imapversion = imapversion;
01358 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01359 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01360 retval->imapversion = imapversion;
01361 } else if (!strcasecmp(var->name, "imapfolder")) {
01362 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01363 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01364 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01365 retval->imapversion = imapversion;
01366 #endif
01367 } else
01368 apply_option(retval, var->name, var->value);
01369 }
01370 }
01371
01372
01373
01374
01375
01376
01377
01378
01379 static int is_valid_dtmf(const char *key)
01380 {
01381 int i;
01382 char *local_key = ast_strdupa(key);
01383
01384 for (i = 0; i < strlen(key); ++i) {
01385 if (!strchr(VALID_DTMF, *local_key)) {
01386 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01387 return 0;
01388 }
01389 local_key++;
01390 }
01391 return 1;
01392 }
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01405 {
01406 struct ast_variable *var;
01407 struct ast_vm_user *retval;
01408
01409 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01410 if (!ivm)
01411 ast_set_flag(retval, VM_ALLOCED);
01412 else
01413 memset(retval, 0, sizeof(*retval));
01414 if (mailbox)
01415 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01416 populate_defaults(retval);
01417 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01418 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01419 else
01420 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01421 if (var) {
01422 apply_options_full(retval, var);
01423 ast_variables_destroy(var);
01424 } else {
01425 if (!ivm)
01426 free_user(retval);
01427 retval = NULL;
01428 }
01429 }
01430 return retval;
01431 }
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01442 {
01443
01444 struct ast_vm_user *vmu = NULL, *cur;
01445 AST_LIST_LOCK(&users);
01446
01447 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01448 context = "default";
01449
01450 AST_LIST_TRAVERSE(&users, cur, list) {
01451 #ifdef IMAP_STORAGE
01452 if (cur->imapversion != imapversion) {
01453 continue;
01454 }
01455 #endif
01456 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01457 break;
01458 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01459 break;
01460 }
01461 if (cur) {
01462
01463 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01464 *vmu = *cur;
01465 if (!ivm) {
01466 vmu->emailbody = ast_strdup(cur->emailbody);
01467 vmu->emailsubject = ast_strdup(cur->emailsubject);
01468 }
01469 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01470 AST_LIST_NEXT(vmu, list) = NULL;
01471 }
01472 } else
01473 vmu = find_user_realtime(ivm, context, mailbox);
01474 AST_LIST_UNLOCK(&users);
01475 return vmu;
01476 }
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01489 {
01490
01491 struct ast_vm_user *cur;
01492 int res = -1;
01493 AST_LIST_LOCK(&users);
01494 AST_LIST_TRAVERSE(&users, cur, list) {
01495 if ((!context || !strcasecmp(context, cur->context)) &&
01496 (!strcasecmp(mailbox, cur->mailbox)))
01497 break;
01498 }
01499 if (cur) {
01500 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01501 res = 0;
01502 }
01503 AST_LIST_UNLOCK(&users);
01504 return res;
01505 }
01506
01507
01508
01509
01510
01511
01512
01513
01514 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01515 {
01516 struct ast_config *cfg = NULL;
01517 struct ast_variable *var = NULL;
01518 struct ast_category *cat = NULL;
01519 char *category = NULL, *value = NULL, *new = NULL;
01520 const char *tmp = NULL;
01521 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01522 char secretfn[PATH_MAX] = "";
01523 int found = 0;
01524
01525 if (!change_password_realtime(vmu, newpassword))
01526 return;
01527
01528
01529 switch (vmu->passwordlocation) {
01530 case OPT_PWLOC_SPOOLDIR:
01531 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01532 if (write_password_to_file(secretfn, newpassword) == 0) {
01533 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01534 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01535 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01536 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01537 break;
01538 } else {
01539 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01540 }
01541
01542 case OPT_PWLOC_VOICEMAILCONF:
01543 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01544 while ((category = ast_category_browse(cfg, category))) {
01545 if (!strcasecmp(category, vmu->context)) {
01546 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01547 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01548 break;
01549 }
01550 value = strstr(tmp, ",");
01551 if (!value) {
01552 new = alloca(strlen(newpassword)+1);
01553 sprintf(new, "%s", newpassword);
01554 } else {
01555 new = alloca((strlen(value) + strlen(newpassword) + 1));
01556 sprintf(new, "%s%s", newpassword, value);
01557 }
01558 if (!(cat = ast_category_get(cfg, category))) {
01559 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01560 break;
01561 }
01562 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01563 found = 1;
01564 }
01565 }
01566
01567 if (found) {
01568 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01569 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01570 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01571 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01572 break;
01573 }
01574 }
01575
01576 case OPT_PWLOC_USERSCONF:
01577
01578
01579 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01580 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01581 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01582 ast_debug(4, "users.conf: %s\n", category);
01583 if (!strcasecmp(category, vmu->mailbox)) {
01584 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01585 ast_debug(3, "looks like we need to make vmsecret!\n");
01586 var = ast_variable_new("vmsecret", newpassword, "");
01587 } else {
01588 var = NULL;
01589 }
01590 new = alloca(strlen(newpassword) + 1);
01591 sprintf(new, "%s", newpassword);
01592 if (!(cat = ast_category_get(cfg, category))) {
01593 ast_debug(4, "failed to get category!\n");
01594 ast_free(var);
01595 break;
01596 }
01597 if (!var) {
01598 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01599 } else {
01600 ast_variable_append(cat, var);
01601 }
01602 found = 1;
01603 break;
01604 }
01605 }
01606
01607 if (found) {
01608 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01609 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01610 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01611 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01612 }
01613 }
01614 }
01615 }
01616
01617 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01618 {
01619 char buf[255];
01620 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01621 ast_debug(1, "External password: %s\n",buf);
01622 if (!ast_safe_system(buf)) {
01623 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01624 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01625
01626 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01627 }
01628 }
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01644 {
01645 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01646 }
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660 static int make_file(char *dest, const int len, const char *dir, const int num)
01661 {
01662 return snprintf(dest, len, "%s/msg%04d", dir, num);
01663 }
01664
01665
01666 static FILE *vm_mkftemp(char *template)
01667 {
01668 FILE *p = NULL;
01669 int pfd = mkstemp(template);
01670 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01671 if (pfd > -1) {
01672 p = fdopen(pfd, "w+");
01673 if (!p) {
01674 close(pfd);
01675 pfd = -1;
01676 }
01677 }
01678 return p;
01679 }
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01690 {
01691 mode_t mode = VOICEMAIL_DIR_MODE;
01692 int res;
01693
01694 make_dir(dest, len, context, ext, folder);
01695 if ((res = ast_mkdir(dest, mode))) {
01696 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01697 return -1;
01698 }
01699 return 0;
01700 }
01701
01702 static const char * const mailbox_folders[] = {
01703 #ifdef IMAP_STORAGE
01704 imapfolder,
01705 #else
01706 "INBOX",
01707 #endif
01708 "Old",
01709 "Work",
01710 "Family",
01711 "Friends",
01712 "Cust1",
01713 "Cust2",
01714 "Cust3",
01715 "Cust4",
01716 "Cust5",
01717 "Deleted",
01718 "Urgent",
01719 };
01720
01721 static const char *mbox(struct ast_vm_user *vmu, int id)
01722 {
01723 #ifdef IMAP_STORAGE
01724 if (vmu && id == 0) {
01725 return vmu->imapfolder;
01726 }
01727 #endif
01728 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01729 }
01730
01731 static int get_folder_by_name(const char *name)
01732 {
01733 size_t i;
01734
01735 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01736 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01737 return i;
01738 }
01739 }
01740
01741 return -1;
01742 }
01743
01744 static void free_user(struct ast_vm_user *vmu)
01745 {
01746 if (ast_test_flag(vmu, VM_ALLOCED)) {
01747
01748 ast_free(vmu->emailbody);
01749 vmu->emailbody = NULL;
01750
01751 ast_free(vmu->emailsubject);
01752 vmu->emailsubject = NULL;
01753
01754 ast_free(vmu);
01755 }
01756 }
01757
01758 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01759
01760 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01761 if (!vms->dh_arraysize) {
01762
01763 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01764 return -1;
01765 }
01766 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01767 return -1;
01768 }
01769 vms->dh_arraysize = arraysize;
01770 } else if (vms->dh_arraysize < arraysize) {
01771 if (!(vms->deleted = ast_realloc(vms->deleted, arraysize * sizeof(int)))) {
01772 return -1;
01773 }
01774 if (!(vms->heard = ast_realloc(vms->heard, arraysize * sizeof(int)))) {
01775 return -1;
01776 }
01777 memset(vms->deleted, 0, arraysize * sizeof(int));
01778 memset(vms->heard, 0, arraysize * sizeof(int));
01779 vms->dh_arraysize = arraysize;
01780 }
01781
01782 return 0;
01783 }
01784
01785
01786
01787 #ifdef IMAP_STORAGE
01788 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01789 {
01790 char arg[10];
01791 struct vm_state *vms;
01792 unsigned long messageNum;
01793
01794
01795 if (msgnum < 0 && !imapgreetings) {
01796 ast_filedelete(file, NULL);
01797 return;
01798 }
01799
01800 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01801 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);
01802 return;
01803 }
01804
01805
01806
01807 messageNum = vms->msgArray[msgnum];
01808 if (messageNum == 0) {
01809 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01810 return;
01811 }
01812 if (option_debug > 2)
01813 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01814
01815 snprintf (arg, sizeof(arg), "%lu", messageNum);
01816 ast_mutex_lock(&vms->lock);
01817 mail_setflag (vms->mailstream, arg, "\\DELETED");
01818 mail_expunge(vms->mailstream);
01819 ast_mutex_unlock(&vms->lock);
01820 }
01821
01822 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01823 {
01824 struct vm_state *vms_p;
01825 char *file, *filename;
01826 char *attachment;
01827 int i;
01828 BODY *body;
01829
01830
01831
01832
01833 if (msgnum > -1 || !imapgreetings) {
01834 return 0;
01835 } else {
01836 file = strrchr(ast_strdupa(dir), '/');
01837 if (file)
01838 *file++ = '\0';
01839 else {
01840 ast_debug (1, "Failed to procure file name from directory passed.\n");
01841 return -1;
01842 }
01843 }
01844
01845
01846 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01847 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01848
01849
01850
01851
01852 if (!(vms_p = create_vm_state_from_user(vmu))) {
01853 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01854 return -1;
01855 }
01856 }
01857
01858
01859 *vms_p->introfn = '\0';
01860
01861 ast_mutex_lock(&vms_p->lock);
01862 init_mailstream(vms_p, GREETINGS_FOLDER);
01863 if (!vms_p->mailstream) {
01864 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01865 ast_mutex_unlock(&vms_p->lock);
01866 return -1;
01867 }
01868
01869
01870 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01871 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01872
01873 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01874 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01875 } else {
01876 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01877 ast_mutex_unlock(&vms_p->lock);
01878 return -1;
01879 }
01880 filename = strsep(&attachment, ".");
01881 if (!strcmp(filename, file)) {
01882 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01883 vms_p->msgArray[vms_p->curmsg] = i + 1;
01884 save_body(body, vms_p, "2", attachment, 0);
01885 ast_mutex_unlock(&vms_p->lock);
01886 return 0;
01887 }
01888 }
01889 ast_mutex_unlock(&vms_p->lock);
01890
01891 return -1;
01892 }
01893
01894 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01895 {
01896 BODY *body;
01897 char *header_content;
01898 char *attachedfilefmt;
01899 char buf[80];
01900 struct vm_state *vms;
01901 char text_file[PATH_MAX];
01902 FILE *text_file_ptr;
01903 int res = 0;
01904 struct ast_vm_user *vmu;
01905
01906 if (!(vmu = find_user(NULL, context, mailbox))) {
01907 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01908 return -1;
01909 }
01910
01911 if (msgnum < 0) {
01912 if (imapgreetings) {
01913 res = imap_retrieve_greeting(dir, msgnum, vmu);
01914 goto exit;
01915 } else {
01916 res = 0;
01917 goto exit;
01918 }
01919 }
01920
01921
01922
01923
01924 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01925
01926
01927
01928
01929
01930
01931
01932 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01933 res = -1;
01934 goto exit;
01935 }
01936
01937 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01938 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01939
01940
01941 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01942 res = 0;
01943 goto exit;
01944 }
01945
01946 if (option_debug > 2)
01947 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01948 if (vms->msgArray[msgnum] == 0) {
01949 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01950 res = -1;
01951 goto exit;
01952 }
01953
01954
01955 ast_mutex_lock(&vms->lock);
01956 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01957 ast_mutex_unlock(&vms->lock);
01958
01959 if (ast_strlen_zero(header_content)) {
01960 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01961 res = -1;
01962 goto exit;
01963 }
01964
01965 ast_mutex_lock(&vms->lock);
01966 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01967 ast_mutex_unlock(&vms->lock);
01968
01969
01970 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01971 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01972 } else {
01973 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01974 res = -1;
01975 goto exit;
01976 }
01977
01978
01979
01980 strsep(&attachedfilefmt, ".");
01981 if (!attachedfilefmt) {
01982 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01983 res = -1;
01984 goto exit;
01985 }
01986
01987 save_body(body, vms, "2", attachedfilefmt, 0);
01988 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01989 *vms->introfn = '\0';
01990 }
01991
01992
01993 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01994
01995 if (!(text_file_ptr = fopen(text_file, "w"))) {
01996 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01997 }
01998
01999 fprintf(text_file_ptr, "%s\n", "[message]");
02000
02001 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02002 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02003 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02004 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02005 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02006 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02007 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02008 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02009 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02010 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02011 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02012 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02013 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02014 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02015 fclose(text_file_ptr);
02016
02017 exit:
02018 free_user(vmu);
02019 return res;
02020 }
02021
02022 static int folder_int(const char *folder)
02023 {
02024
02025 if (!folder) {
02026 return 0;
02027 }
02028 if (!strcasecmp(folder, imapfolder)) {
02029 return 0;
02030 } else if (!strcasecmp(folder, "Old")) {
02031 return 1;
02032 } else if (!strcasecmp(folder, "Work")) {
02033 return 2;
02034 } else if (!strcasecmp(folder, "Family")) {
02035 return 3;
02036 } else if (!strcasecmp(folder, "Friends")) {
02037 return 4;
02038 } else if (!strcasecmp(folder, "Cust1")) {
02039 return 5;
02040 } else if (!strcasecmp(folder, "Cust2")) {
02041 return 6;
02042 } else if (!strcasecmp(folder, "Cust3")) {
02043 return 7;
02044 } else if (!strcasecmp(folder, "Cust4")) {
02045 return 8;
02046 } else if (!strcasecmp(folder, "Cust5")) {
02047 return 9;
02048 } else if (!strcasecmp(folder, "Urgent")) {
02049 return 11;
02050 } else {
02051 return 0;
02052 }
02053 }
02054
02055 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02056 {
02057 SEARCHPGM *pgm;
02058 SEARCHHEADER *hdr;
02059
02060 struct ast_vm_user *vmu, vmus;
02061 struct vm_state *vms_p;
02062 int ret = 0;
02063 int fold = folder_int(folder);
02064 int urgent = 0;
02065
02066
02067 if (fold == 11) {
02068 fold = NEW_FOLDER;
02069 urgent = 1;
02070 }
02071
02072 if (ast_strlen_zero(mailbox))
02073 return 0;
02074
02075
02076 vmu = find_user(&vmus, context, mailbox);
02077 if (!vmu) {
02078 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02079 return -1;
02080 } else {
02081
02082 if (vmu->imapuser[0] == '\0') {
02083 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02084 return -1;
02085 }
02086 }
02087
02088
02089 if (vmu->imapuser[0] == '\0') {
02090 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02091 free_user(vmu);
02092 return -1;
02093 }
02094
02095
02096 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02097 if (!vms_p) {
02098 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02099 }
02100 if (vms_p) {
02101 ast_debug(3, "Returning before search - user is logged in\n");
02102 if (fold == 0) {
02103 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02104 }
02105 if (fold == 1) {
02106 return vms_p->oldmessages;
02107 }
02108 }
02109
02110
02111 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02112 if (!vms_p) {
02113 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02114 }
02115
02116 if (!vms_p) {
02117 vms_p = create_vm_state_from_user(vmu);
02118 }
02119 ret = init_mailstream(vms_p, fold);
02120 if (!vms_p->mailstream) {
02121 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02122 return -1;
02123 }
02124 if (ret == 0) {
02125 ast_mutex_lock(&vms_p->lock);
02126 pgm = mail_newsearchpgm ();
02127 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02128 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02129 pgm->header = hdr;
02130 if (fold != OLD_FOLDER) {
02131 pgm->unseen = 1;
02132 pgm->seen = 0;
02133 }
02134
02135
02136
02137 else {
02138 pgm->unseen = 0;
02139 pgm->seen = 1;
02140 }
02141
02142 if (fold == NEW_FOLDER) {
02143 if (urgent) {
02144 pgm->flagged = 1;
02145 pgm->unflagged = 0;
02146 } else {
02147 pgm->flagged = 0;
02148 pgm->unflagged = 1;
02149 }
02150 }
02151 pgm->undeleted = 1;
02152 pgm->deleted = 0;
02153
02154 vms_p->vmArrayIndex = 0;
02155 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02156 if (fold == 0 && urgent == 0)
02157 vms_p->newmessages = vms_p->vmArrayIndex;
02158 if (fold == 1)
02159 vms_p->oldmessages = vms_p->vmArrayIndex;
02160 if (fold == 0 && urgent == 1)
02161 vms_p->urgentmessages = vms_p->vmArrayIndex;
02162
02163 mail_free_searchpgm(&pgm);
02164 ast_mutex_unlock(&vms_p->lock);
02165 vms_p->updated = 0;
02166 return vms_p->vmArrayIndex;
02167 } else {
02168 ast_mutex_lock(&vms_p->lock);
02169 mail_ping(vms_p->mailstream);
02170 ast_mutex_unlock(&vms_p->lock);
02171 }
02172 return 0;
02173 }
02174
02175 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02176 {
02177
02178 check_quota(vms, vmu->imapfolder);
02179 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02180 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02181 ast_play_and_wait(chan, "vm-mailboxfull");
02182 return -1;
02183 }
02184
02185
02186 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));
02187 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02188 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02189 ast_play_and_wait(chan, "vm-mailboxfull");
02190 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02191 return -1;
02192 }
02193
02194 return 0;
02195 }
02196
02197
02198
02199
02200
02201
02202
02203
02204
02205
02206 static int messagecount(const char *context, const char *mailbox, const char *folder)
02207 {
02208 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02209 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02210 } else {
02211 return __messagecount(context, mailbox, folder);
02212 }
02213 }
02214
02215 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)
02216 {
02217 char *myserveremail = serveremail;
02218 char fn[PATH_MAX];
02219 char introfn[PATH_MAX];
02220 char mailbox[256];
02221 char *stringp;
02222 FILE *p = NULL;
02223 char tmp[80] = "/tmp/astmail-XXXXXX";
02224 long len;
02225 void *buf;
02226 int tempcopy = 0;
02227 STRING str;
02228 int ret;
02229 char *imap_flags = NIL;
02230 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02231 int box = NEW_FOLDER;
02232
02233
02234 if (msgnum < 0) {
02235 if(!imapgreetings) {
02236 return 0;
02237 } else {
02238 box = GREETINGS_FOLDER;
02239 }
02240 }
02241
02242 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02243 return -1;
02244 }
02245
02246
02247 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02248 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02249 imap_flags = "\\FLAGGED";
02250 }
02251
02252
02253 fmt = ast_strdupa(fmt);
02254 stringp = fmt;
02255 strsep(&stringp, "|");
02256
02257 if (!ast_strlen_zero(vmu->serveremail))
02258 myserveremail = vmu->serveremail;
02259
02260 if (msgnum > -1)
02261 make_file(fn, sizeof(fn), dir, msgnum);
02262 else
02263 ast_copy_string (fn, dir, sizeof(fn));
02264
02265 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02266 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02267 *introfn = '\0';
02268 }
02269
02270 if (ast_strlen_zero(vmu->email)) {
02271
02272
02273
02274
02275
02276 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02277 tempcopy = 1;
02278 }
02279
02280 if (!strcmp(fmt, "wav49"))
02281 fmt = "WAV";
02282 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02283
02284
02285
02286 if (!(p = vm_mkftemp(tmp))) {
02287 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02288 if (tempcopy)
02289 *(vmu->email) = '\0';
02290 return -1;
02291 }
02292
02293 if (msgnum < 0 && imapgreetings) {
02294 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02295 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02296 return -1;
02297 }
02298 imap_delete_old_greeting(fn, vms);
02299 }
02300
02301 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02302 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02303 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02304 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02305
02306 len = ftell(p);
02307 rewind(p);
02308 if (!(buf = ast_malloc(len + 1))) {
02309 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02310 fclose(p);
02311 if (tempcopy)
02312 *(vmu->email) = '\0';
02313 return -1;
02314 }
02315 if (fread(buf, len, 1, p) < len) {
02316 if (ferror(p)) {
02317 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02318 return -1;
02319 }
02320 }
02321 ((char *) buf)[len] = '\0';
02322 INIT(&str, mail_string, buf, len);
02323 ret = init_mailstream(vms, box);
02324 if (ret == 0) {
02325 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02326 ast_mutex_lock(&vms->lock);
02327 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02328 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02329 ast_mutex_unlock(&vms->lock);
02330 fclose(p);
02331 unlink(tmp);
02332 ast_free(buf);
02333 } else {
02334 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02335 fclose(p);
02336 unlink(tmp);
02337 ast_free(buf);
02338 return -1;
02339 }
02340 ast_debug(3, "%s stored\n", fn);
02341
02342 if (tempcopy)
02343 *(vmu->email) = '\0';
02344 inprocess_count(vmu->mailbox, vmu->context, -1);
02345 return 0;
02346
02347 }
02348
02349
02350
02351
02352
02353
02354
02355
02356
02357
02358
02359
02360
02361
02362 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02363 {
02364 char tmp[PATH_MAX] = "";
02365 char *mailboxnc;
02366 char *context;
02367 char *mb;
02368 char *cur;
02369 if (newmsgs)
02370 *newmsgs = 0;
02371 if (oldmsgs)
02372 *oldmsgs = 0;
02373 if (urgentmsgs)
02374 *urgentmsgs = 0;
02375
02376 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02377
02378 if (ast_strlen_zero(mailbox_context))
02379 return 0;
02380
02381 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02382 context = strchr(tmp, '@');
02383 if (strchr(mailbox_context, ',')) {
02384 int tmpnew, tmpold, tmpurgent;
02385 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02386 mb = tmp;
02387 while ((cur = strsep(&mb, ", "))) {
02388 if (!ast_strlen_zero(cur)) {
02389 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02390 return -1;
02391 else {
02392 if (newmsgs)
02393 *newmsgs += tmpnew;
02394 if (oldmsgs)
02395 *oldmsgs += tmpold;
02396 if (urgentmsgs)
02397 *urgentmsgs += tmpurgent;
02398 }
02399 }
02400 }
02401 return 0;
02402 }
02403 if (context) {
02404 *context = '\0';
02405 mailboxnc = tmp;
02406 context++;
02407 } else {
02408 context = "default";
02409 mailboxnc = (char *) mailbox_context;
02410 }
02411
02412 if (newmsgs) {
02413 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02414 if (!vmu) {
02415 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02416 return -1;
02417 }
02418 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02419 return -1;
02420 }
02421 }
02422 if (oldmsgs) {
02423 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02424 return -1;
02425 }
02426 }
02427 if (urgentmsgs) {
02428 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02429 return -1;
02430 }
02431 }
02432 return 0;
02433 }
02434
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445 static int has_voicemail(const char *mailbox, const char *folder)
02446 {
02447 char tmp[256], *tmp2, *box, *context;
02448 ast_copy_string(tmp, mailbox, sizeof(tmp));
02449 tmp2 = tmp;
02450 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02451 while ((box = strsep(&tmp2, ",&"))) {
02452 if (!ast_strlen_zero(box)) {
02453 if (has_voicemail(box, folder)) {
02454 return 1;
02455 }
02456 }
02457 }
02458 }
02459 if ((context = strchr(tmp, '@'))) {
02460 *context++ = '\0';
02461 } else {
02462 context = "default";
02463 }
02464 return __messagecount(context, tmp, folder) ? 1 : 0;
02465 }
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482 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)
02483 {
02484 struct vm_state *sendvms = NULL, *destvms = NULL;
02485 char messagestring[10];
02486 if (msgnum >= recip->maxmsg) {
02487 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02488 return -1;
02489 }
02490 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02491 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02492 return -1;
02493 }
02494 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02495 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02496 return -1;
02497 }
02498 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02499 ast_mutex_lock(&sendvms->lock);
02500 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02501 ast_mutex_unlock(&sendvms->lock);
02502 return 0;
02503 }
02504 ast_mutex_unlock(&sendvms->lock);
02505 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02506 return -1;
02507 }
02508
02509 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02510 {
02511 char tmp[256], *t = tmp;
02512 size_t left = sizeof(tmp);
02513
02514 if (box == OLD_FOLDER) {
02515 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02516 } else {
02517 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02518 }
02519
02520 if (box == NEW_FOLDER) {
02521 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02522 } else {
02523 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02524 }
02525
02526
02527 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02528
02529
02530 if (!ast_strlen_zero(authuser))
02531 ast_build_string(&t, &left, "/authuser=%s", authuser);
02532
02533
02534 if (!ast_strlen_zero(imapflags))
02535 ast_build_string(&t, &left, "/%s", imapflags);
02536
02537
02538 #if 1
02539 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02540 #else
02541 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02542 #endif
02543 if (box == NEW_FOLDER || box == OLD_FOLDER)
02544 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02545 else if (box == GREETINGS_FOLDER)
02546 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02547 else {
02548 if (!ast_strlen_zero(imapparentfolder)) {
02549
02550 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02551 } else {
02552 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02553 }
02554 }
02555 }
02556
02557 static int init_mailstream(struct vm_state *vms, int box)
02558 {
02559 MAILSTREAM *stream = NIL;
02560 long debug;
02561 char tmp[256];
02562
02563 if (!vms) {
02564 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02565 return -1;
02566 }
02567 if (option_debug > 2)
02568 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02569 if (vms->mailstream == NIL || !vms->mailstream) {
02570 if (option_debug)
02571 ast_log(LOG_DEBUG, "mailstream not set.\n");
02572 } else {
02573 stream = vms->mailstream;
02574 }
02575
02576 debug = NIL;
02577
02578 if (delimiter == '\0') {
02579 char *cp;
02580 #ifdef USE_SYSTEM_IMAP
02581 #include <imap/linkage.c>
02582 #elif defined(USE_SYSTEM_CCLIENT)
02583 #include <c-client/linkage.c>
02584 #else
02585 #include "linkage.c"
02586 #endif
02587
02588 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02589 ast_mutex_lock(&vms->lock);
02590 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02591 ast_mutex_unlock(&vms->lock);
02592 if (stream == NIL) {
02593 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02594 return -1;
02595 }
02596 get_mailbox_delimiter(stream);
02597
02598 for (cp = vms->imapfolder; *cp; cp++)
02599 if (*cp == '/')
02600 *cp = delimiter;
02601 }
02602
02603 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02604 if (option_debug > 2)
02605 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02606 ast_mutex_lock(&vms->lock);
02607 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02608 ast_mutex_unlock(&vms->lock);
02609 if (vms->mailstream == NIL) {
02610 return -1;
02611 } else {
02612 return 0;
02613 }
02614 }
02615
02616 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02617 {
02618 SEARCHPGM *pgm;
02619 SEARCHHEADER *hdr;
02620 int ret, urgent = 0;
02621
02622
02623 if (box == 11) {
02624 box = NEW_FOLDER;
02625 urgent = 1;
02626 }
02627
02628 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02629 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02630 vms->imapversion = vmu->imapversion;
02631 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02632
02633 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02634 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02635 return -1;
02636 }
02637
02638 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02639
02640
02641 if (box == 0) {
02642 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02643 check_quota(vms, (char *) mbox(vmu, box));
02644 }
02645
02646 ast_mutex_lock(&vms->lock);
02647 pgm = mail_newsearchpgm();
02648
02649
02650 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02651 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02652 pgm->header = hdr;
02653 pgm->deleted = 0;
02654 pgm->undeleted = 1;
02655
02656
02657 if (box == NEW_FOLDER && urgent == 1) {
02658 pgm->unseen = 1;
02659 pgm->seen = 0;
02660 pgm->flagged = 1;
02661 pgm->unflagged = 0;
02662 } else if (box == NEW_FOLDER && urgent == 0) {
02663 pgm->unseen = 1;
02664 pgm->seen = 0;
02665 pgm->flagged = 0;
02666 pgm->unflagged = 1;
02667 } else if (box == OLD_FOLDER) {
02668 pgm->seen = 1;
02669 pgm->unseen = 0;
02670 }
02671
02672 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02673
02674 vms->vmArrayIndex = 0;
02675 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02676 vms->lastmsg = vms->vmArrayIndex - 1;
02677 mail_free_searchpgm(&pgm);
02678
02679
02680
02681
02682 if (box == 0 && !vms->dh_arraysize) {
02683 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02684 }
02685 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02686 ast_mutex_unlock(&vms->lock);
02687 return -1;
02688 }
02689
02690 ast_mutex_unlock(&vms->lock);
02691 return 0;
02692 }
02693
02694 static void write_file(char *filename, char *buffer, unsigned long len)
02695 {
02696 FILE *output;
02697
02698 output = fopen (filename, "w");
02699 if (fwrite(buffer, len, 1, output) != 1) {
02700 if (ferror(output)) {
02701 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02702 }
02703 }
02704 fclose (output);
02705 }
02706
02707 static void update_messages_by_imapuser(const char *user, unsigned long number)
02708 {
02709 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02710
02711 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02712 return;
02713 }
02714
02715 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02716 vms->msgArray[vms->vmArrayIndex++] = number;
02717 }
02718
02719 void mm_searched(MAILSTREAM *stream, unsigned long number)
02720 {
02721 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02722
02723 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02724 return;
02725
02726 update_messages_by_imapuser(user, number);
02727 }
02728
02729 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02730 {
02731 struct ast_variable *var;
02732 struct ast_vm_user *vmu;
02733
02734 vmu = ast_calloc(1, sizeof *vmu);
02735 if (!vmu)
02736 return NULL;
02737 ast_set_flag(vmu, VM_ALLOCED);
02738 populate_defaults(vmu);
02739
02740 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02741 if (var) {
02742 apply_options_full(vmu, var);
02743 ast_variables_destroy(var);
02744 return vmu;
02745 } else {
02746 ast_free(vmu);
02747 return NULL;
02748 }
02749 }
02750
02751
02752
02753 void mm_exists(MAILSTREAM * stream, unsigned long number)
02754 {
02755
02756 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02757 if (number == 0) return;
02758 set_update(stream);
02759 }
02760
02761
02762 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02763 {
02764
02765 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02766 if (number == 0) return;
02767 set_update(stream);
02768 }
02769
02770
02771 void mm_flags(MAILSTREAM * stream, unsigned long number)
02772 {
02773
02774 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02775 if (number == 0) return;
02776 set_update(stream);
02777 }
02778
02779
02780 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02781 {
02782 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02783 mm_log (string, errflg);
02784 }
02785
02786
02787 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02788 {
02789 if (delimiter == '\0') {
02790 delimiter = delim;
02791 }
02792
02793 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02794 if (attributes & LATT_NOINFERIORS)
02795 ast_debug(5, "no inferiors\n");
02796 if (attributes & LATT_NOSELECT)
02797 ast_debug(5, "no select\n");
02798 if (attributes & LATT_MARKED)
02799 ast_debug(5, "marked\n");
02800 if (attributes & LATT_UNMARKED)
02801 ast_debug(5, "unmarked\n");
02802 }
02803
02804
02805 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02806 {
02807 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02808 if (attributes & LATT_NOINFERIORS)
02809 ast_debug(5, "no inferiors\n");
02810 if (attributes & LATT_NOSELECT)
02811 ast_debug(5, "no select\n");
02812 if (attributes & LATT_MARKED)
02813 ast_debug(5, "marked\n");
02814 if (attributes & LATT_UNMARKED)
02815 ast_debug(5, "unmarked\n");
02816 }
02817
02818
02819 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02820 {
02821 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02822 if (status->flags & SA_MESSAGES)
02823 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02824 if (status->flags & SA_RECENT)
02825 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02826 if (status->flags & SA_UNSEEN)
02827 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02828 if (status->flags & SA_UIDVALIDITY)
02829 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02830 if (status->flags & SA_UIDNEXT)
02831 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02832 ast_log(AST_LOG_NOTICE, "\n");
02833 }
02834
02835
02836 void mm_log(char *string, long errflg)
02837 {
02838 switch ((short) errflg) {
02839 case NIL:
02840 ast_debug(1, "IMAP Info: %s\n", string);
02841 break;
02842 case PARSE:
02843 case WARN:
02844 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02845 break;
02846 case ERROR:
02847 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02848 break;
02849 }
02850 }
02851
02852
02853 void mm_dlog(char *string)
02854 {
02855 ast_log(AST_LOG_NOTICE, "%s\n", string);
02856 }
02857
02858
02859 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02860 {
02861 struct ast_vm_user *vmu;
02862
02863 ast_debug(4, "Entering callback mm_login\n");
02864
02865 ast_copy_string(user, mb->user, MAILTMPLEN);
02866
02867
02868 if (!ast_strlen_zero(authpassword)) {
02869 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02870 } else {
02871 AST_LIST_TRAVERSE(&users, vmu, list) {
02872 if (!strcasecmp(mb->user, vmu->imapuser)) {
02873 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02874 break;
02875 }
02876 }
02877 if (!vmu) {
02878 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02879 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02880 free_user(vmu);
02881 }
02882 }
02883 }
02884 }
02885
02886
02887 void mm_critical(MAILSTREAM * stream)
02888 {
02889 }
02890
02891
02892 void mm_nocritical(MAILSTREAM * stream)
02893 {
02894 }
02895
02896
02897 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02898 {
02899 kill (getpid (), SIGSTOP);
02900 return NIL;
02901 }
02902
02903
02904 void mm_fatal(char *string)
02905 {
02906 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02907 }
02908
02909
02910 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02911 {
02912 struct vm_state *vms;
02913 char *mailbox = stream->mailbox, *user;
02914 char buf[1024] = "";
02915 unsigned long usage = 0, limit = 0;
02916
02917 while (pquota) {
02918 usage = pquota->usage;
02919 limit = pquota->limit;
02920 pquota = pquota->next;
02921 }
02922
02923 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)))) {
02924 ast_log(AST_LOG_ERROR, "No state found.\n");
02925 return;
02926 }
02927
02928 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02929
02930 vms->quota_usage = usage;
02931 vms->quota_limit = limit;
02932 }
02933
02934 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02935 {
02936 char *start, *eol_pnt;
02937 int taglen;
02938
02939 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02940 return NULL;
02941
02942 taglen = strlen(tag) + 1;
02943 if (taglen < 1)
02944 return NULL;
02945
02946 if (!(start = strstr(header, tag)))
02947 return NULL;
02948
02949
02950 memset(buf, 0, len);
02951
02952 ast_copy_string(buf, start+taglen, len);
02953 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02954 *eol_pnt = '\0';
02955 return buf;
02956 }
02957
02958 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02959 {
02960 char *start, *quote, *eol_pnt;
02961
02962 if (ast_strlen_zero(mailbox))
02963 return NULL;
02964
02965 if (!(start = strstr(mailbox, "/user=")))
02966 return NULL;
02967
02968 ast_copy_string(buf, start+6, len);
02969
02970 if (!(quote = strchr(buf, '\"'))) {
02971 if (!(eol_pnt = strchr(buf, '/')))
02972 eol_pnt = strchr(buf,'}');
02973 *eol_pnt = '\0';
02974 return buf;
02975 } else {
02976 eol_pnt = strchr(buf+1,'\"');
02977 *eol_pnt = '\0';
02978 return buf+1;
02979 }
02980 }
02981
02982 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02983 {
02984 struct vm_state *vms_p;
02985
02986 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02987 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02988 return vms_p;
02989 }
02990 if (option_debug > 4)
02991 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02992 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02993 return NULL;
02994 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02995 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
02996 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02997 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02998 vms_p->mailstream = NIL;
02999 vms_p->imapversion = vmu->imapversion;
03000 if (option_debug > 4)
03001 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03002 vms_p->updated = 1;
03003
03004 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03005 init_vm_state(vms_p);
03006 vmstate_insert(vms_p);
03007 return vms_p;
03008 }
03009
03010 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03011 {
03012 struct vmstate *vlist = NULL;
03013
03014 if (interactive) {
03015 struct vm_state *vms;
03016 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03017 vms = pthread_getspecific(ts_vmstate.key);
03018 return vms;
03019 }
03020
03021 AST_LIST_LOCK(&vmstates);
03022 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03023 if (!vlist->vms) {
03024 ast_debug(3, "error: vms is NULL for %s\n", user);
03025 continue;
03026 }
03027 if (vlist->vms->imapversion != imapversion) {
03028 continue;
03029 }
03030 if (!vlist->vms->imapuser) {
03031 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03032 continue;
03033 }
03034
03035 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03036 AST_LIST_UNLOCK(&vmstates);
03037 return vlist->vms;
03038 }
03039 }
03040 AST_LIST_UNLOCK(&vmstates);
03041
03042 ast_debug(3, "%s not found in vmstates\n", user);
03043
03044 return NULL;
03045 }
03046
03047 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03048 {
03049
03050 struct vmstate *vlist = NULL;
03051 const char *local_context = S_OR(context, "default");
03052
03053 if (interactive) {
03054 struct vm_state *vms;
03055 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03056 vms = pthread_getspecific(ts_vmstate.key);
03057 return vms;
03058 }
03059
03060 AST_LIST_LOCK(&vmstates);
03061 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03062 if (!vlist->vms) {
03063 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03064 continue;
03065 }
03066 if (vlist->vms->imapversion != imapversion) {
03067 continue;
03068 }
03069 if (!vlist->vms->username || !vlist->vms->context) {
03070 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03071 continue;
03072 }
03073
03074 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);
03075
03076 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03077 ast_debug(3, "Found it!\n");
03078 AST_LIST_UNLOCK(&vmstates);
03079 return vlist->vms;
03080 }
03081 }
03082 AST_LIST_UNLOCK(&vmstates);
03083
03084 ast_debug(3, "%s not found in vmstates\n", mailbox);
03085
03086 return NULL;
03087 }
03088
03089 static void vmstate_insert(struct vm_state *vms)
03090 {
03091 struct vmstate *v;
03092 struct vm_state *altvms;
03093
03094
03095
03096
03097 if (vms->interactive == 1) {
03098 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03099 if (altvms) {
03100 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03101 vms->newmessages = altvms->newmessages;
03102 vms->oldmessages = altvms->oldmessages;
03103 vms->vmArrayIndex = altvms->vmArrayIndex;
03104 vms->lastmsg = altvms->lastmsg;
03105 vms->curmsg = altvms->curmsg;
03106
03107 vms->persist_vms = altvms;
03108
03109 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03110 vms->mailstream = altvms->mailstream;
03111 #else
03112 vms->mailstream = NIL;
03113 #endif
03114 }
03115 return;
03116 }
03117
03118 if (!(v = ast_calloc(1, sizeof(*v))))
03119 return;
03120
03121 v->vms = vms;
03122
03123 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03124
03125 AST_LIST_LOCK(&vmstates);
03126 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03127 AST_LIST_UNLOCK(&vmstates);
03128 }
03129
03130 static void vmstate_delete(struct vm_state *vms)
03131 {
03132 struct vmstate *vc = NULL;
03133 struct vm_state *altvms = NULL;
03134
03135
03136
03137 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03138 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03139 altvms->newmessages = vms->newmessages;
03140 altvms->oldmessages = vms->oldmessages;
03141 altvms->updated = 1;
03142 vms->mailstream = mail_close(vms->mailstream);
03143
03144
03145 return;
03146 }
03147
03148 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03149
03150 AST_LIST_LOCK(&vmstates);
03151 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03152 if (vc->vms == vms) {
03153 AST_LIST_REMOVE_CURRENT(list);
03154 break;
03155 }
03156 }
03157 AST_LIST_TRAVERSE_SAFE_END
03158 AST_LIST_UNLOCK(&vmstates);
03159
03160 if (vc) {
03161 ast_mutex_destroy(&vc->vms->lock);
03162 ast_free(vc);
03163 }
03164 else
03165 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03166 }
03167
03168 static void set_update(MAILSTREAM * stream)
03169 {
03170 struct vm_state *vms;
03171 char *mailbox = stream->mailbox, *user;
03172 char buf[1024] = "";
03173
03174 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03175 if (user && option_debug > 2)
03176 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03177 return;
03178 }
03179
03180 ast_debug(3, "User %s mailbox set for update.\n", user);
03181
03182 vms->updated = 1;
03183 }
03184
03185 static void init_vm_state(struct vm_state *vms)
03186 {
03187 int x;
03188 vms->vmArrayIndex = 0;
03189 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03190 vms->msgArray[x] = 0;
03191 }
03192 ast_mutex_init(&vms->lock);
03193 }
03194
03195 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03196 {
03197 char *body_content;
03198 char *body_decoded;
03199 char *fn = is_intro ? vms->introfn : vms->fn;
03200 unsigned long len;
03201 unsigned long newlen;
03202 char filename[256];
03203
03204 if (!body || body == NIL)
03205 return -1;
03206
03207 ast_mutex_lock(&vms->lock);
03208 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03209 ast_mutex_unlock(&vms->lock);
03210 if (body_content != NIL) {
03211 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03212
03213 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03214
03215 if (!newlen) {
03216 return -1;
03217 }
03218 write_file(filename, (char *) body_decoded, newlen);
03219 } else {
03220 ast_debug(5, "Body of message is NULL.\n");
03221 return -1;
03222 }
03223 return 0;
03224 }
03225
03226
03227
03228
03229
03230
03231
03232
03233 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03234 char tmp[50];
03235 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03236 mail_list(stream, tmp, "*");
03237 }
03238
03239
03240
03241
03242
03243
03244
03245
03246 static void check_quota(struct vm_state *vms, char *mailbox) {
03247 ast_mutex_lock(&vms->lock);
03248 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03249 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03250 if (vms && vms->mailstream != NULL) {
03251 imap_getquotaroot(vms->mailstream, mailbox);
03252 } else {
03253 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03254 }
03255 ast_mutex_unlock(&vms->lock);
03256 }
03257
03258 #endif
03259
03260
03261
03262
03263
03264 static int vm_lock_path(const char *path)
03265 {
03266 switch (ast_lock_path(path)) {
03267 case AST_LOCK_TIMEOUT:
03268 return -1;
03269 default:
03270 return 0;
03271 }
03272 }
03273
03274
03275 #ifdef ODBC_STORAGE
03276 struct generic_prepare_struct {
03277 char *sql;
03278 int argc;
03279 char **argv;
03280 };
03281
03282 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03283 {
03284 struct generic_prepare_struct *gps = data;
03285 int res, i;
03286 SQLHSTMT stmt;
03287
03288 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03289 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03290 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03291 return NULL;
03292 }
03293 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03294 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03295 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03296 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03297 return NULL;
03298 }
03299 for (i = 0; i < gps->argc; i++)
03300 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03301
03302 return stmt;
03303 }
03304
03305
03306
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319 static int retrieve_file(char *dir, int msgnum)
03320 {
03321 int x = 0;
03322 int res;
03323 int fd = -1;
03324 size_t fdlen = 0;
03325 void *fdm = MAP_FAILED;
03326 SQLSMALLINT colcount = 0;
03327 SQLHSTMT stmt;
03328 char sql[PATH_MAX];
03329 char fmt[80]="";
03330 char *c;
03331 char coltitle[256];
03332 SQLSMALLINT collen;
03333 SQLSMALLINT datatype;
03334 SQLSMALLINT decimaldigits;
03335 SQLSMALLINT nullable;
03336 SQLULEN colsize;
03337 SQLLEN colsize2;
03338 FILE *f = NULL;
03339 char rowdata[80];
03340 char fn[PATH_MAX];
03341 char full_fn[PATH_MAX];
03342 char msgnums[80];
03343 char *argv[] = { dir, msgnums };
03344 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03345
03346 struct odbc_obj *obj;
03347 obj = ast_odbc_request_obj(odbc_database, 0);
03348 if (obj) {
03349 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03350 c = strchr(fmt, '|');
03351 if (c)
03352 *c = '\0';
03353 if (!strcasecmp(fmt, "wav49"))
03354 strcpy(fmt, "WAV");
03355 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03356 if (msgnum > -1)
03357 make_file(fn, sizeof(fn), dir, msgnum);
03358 else
03359 ast_copy_string(fn, dir, sizeof(fn));
03360
03361
03362 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03363
03364 if (!(f = fopen(full_fn, "w+"))) {
03365 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03366 goto yuck;
03367 }
03368
03369 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03370 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03371 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03372 if (!stmt) {
03373 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03374 ast_odbc_release_obj(obj);
03375 goto yuck;
03376 }
03377 res = SQLFetch(stmt);
03378 if (res == SQL_NO_DATA) {
03379 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03380 ast_odbc_release_obj(obj);
03381 goto yuck;
03382 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03383 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03384 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03385 ast_odbc_release_obj(obj);
03386 goto yuck;
03387 }
03388 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03389 if (fd < 0) {
03390 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03391 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03392 ast_odbc_release_obj(obj);
03393 goto yuck;
03394 }
03395 res = SQLNumResultCols(stmt, &colcount);
03396 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03397 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03398 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03399 ast_odbc_release_obj(obj);
03400 goto yuck;
03401 }
03402 if (f)
03403 fprintf(f, "[message]\n");
03404 for (x = 0; x < colcount; x++) {
03405 rowdata[0] = '\0';
03406 colsize = 0;
03407 collen = sizeof(coltitle);
03408 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03409 &datatype, &colsize, &decimaldigits, &nullable);
03410 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03411 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03412 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03413 ast_odbc_release_obj(obj);
03414 goto yuck;
03415 }
03416 if (!strcasecmp(coltitle, "recording")) {
03417 off_t offset;
03418 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03419 fdlen = colsize2;
03420 if (fd > -1) {
03421 char tmp[1]="";
03422 lseek(fd, fdlen - 1, SEEK_SET);
03423 if (write(fd, tmp, 1) != 1) {
03424 close(fd);
03425 fd = -1;
03426 continue;
03427 }
03428
03429 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03430 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03431 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03432 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03433 ast_odbc_release_obj(obj);
03434 goto yuck;
03435 } else {
03436 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03437 munmap(fdm, CHUNKSIZE);
03438 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03439 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03440 unlink(full_fn);
03441 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03442 ast_odbc_release_obj(obj);
03443 goto yuck;
03444 }
03445 }
03446 }
03447 if (truncate(full_fn, fdlen) < 0) {
03448 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03449 }
03450 }
03451 } else {
03452 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03453 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03454 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03455 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03456 ast_odbc_release_obj(obj);
03457 goto yuck;
03458 }
03459 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03460 fprintf(f, "%s=%s\n", coltitle, rowdata);
03461 }
03462 }
03463 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03464 ast_odbc_release_obj(obj);
03465 } else
03466 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03467 yuck:
03468 if (f)
03469 fclose(f);
03470 if (fd > -1)
03471 close(fd);
03472 return x - 1;
03473 }
03474
03475
03476
03477
03478
03479
03480
03481
03482
03483
03484
03485
03486 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03487 {
03488 int x = 0;
03489 int res;
03490 SQLHSTMT stmt;
03491 char sql[PATH_MAX];
03492 char rowdata[20];
03493 char *argv[] = { dir };
03494 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03495
03496 struct odbc_obj *obj;
03497 obj = ast_odbc_request_obj(odbc_database, 0);
03498 if (obj) {
03499 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03500
03501 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03502 if (!stmt) {
03503 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03504 ast_odbc_release_obj(obj);
03505 goto yuck;
03506 }
03507 res = SQLFetch(stmt);
03508 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03509 if (res == SQL_NO_DATA) {
03510 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03511 } else {
03512 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03513 }
03514
03515 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03516 ast_odbc_release_obj(obj);
03517 goto yuck;
03518 }
03519 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03520 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03521 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03522 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03523 ast_odbc_release_obj(obj);
03524 goto yuck;
03525 }
03526 if (sscanf(rowdata, "%30d", &x) != 1)
03527 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03528 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03529 ast_odbc_release_obj(obj);
03530 return x;
03531 } else
03532 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03533 yuck:
03534 return x - 1;
03535 }
03536
03537
03538
03539
03540
03541
03542
03543
03544
03545
03546 static int message_exists(char *dir, int msgnum)
03547 {
03548 int x = 0;
03549 int res;
03550 SQLHSTMT stmt;
03551 char sql[PATH_MAX];
03552 char rowdata[20];
03553 char msgnums[20];
03554 char *argv[] = { dir, msgnums };
03555 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03556
03557 struct odbc_obj *obj;
03558 obj = ast_odbc_request_obj(odbc_database, 0);
03559 if (obj) {
03560 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03561 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03562 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03563 if (!stmt) {
03564 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03565 ast_odbc_release_obj(obj);
03566 goto yuck;
03567 }
03568 res = SQLFetch(stmt);
03569 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03570 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03571 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03572 ast_odbc_release_obj(obj);
03573 goto yuck;
03574 }
03575 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03576 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03577 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03578 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03579 ast_odbc_release_obj(obj);
03580 goto yuck;
03581 }
03582 if (sscanf(rowdata, "%30d", &x) != 1)
03583 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03584 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03585 ast_odbc_release_obj(obj);
03586 } else
03587 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03588 yuck:
03589 return x;
03590 }
03591
03592
03593
03594
03595
03596
03597
03598
03599
03600
03601 static int count_messages(struct ast_vm_user *vmu, char *dir)
03602 {
03603 int x = 0;
03604 int res;
03605 SQLHSTMT stmt;
03606 char sql[PATH_MAX];
03607 char rowdata[20];
03608 char *argv[] = { dir };
03609 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03610
03611 struct odbc_obj *obj;
03612 obj = ast_odbc_request_obj(odbc_database, 0);
03613 if (obj) {
03614 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03615 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03616 if (!stmt) {
03617 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03618 ast_odbc_release_obj(obj);
03619 goto yuck;
03620 }
03621 res = SQLFetch(stmt);
03622 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03623 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03624 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03625 ast_odbc_release_obj(obj);
03626 goto yuck;
03627 }
03628 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03629 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03630 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03631 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03632 ast_odbc_release_obj(obj);
03633 goto yuck;
03634 }
03635 if (sscanf(rowdata, "%30d", &x) != 1)
03636 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03637 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03638 ast_odbc_release_obj(obj);
03639 return x;
03640 } else
03641 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03642 yuck:
03643 return x - 1;
03644
03645 }
03646
03647
03648
03649
03650
03651
03652
03653
03654
03655
03656
03657 static void delete_file(const char *sdir, int smsg)
03658 {
03659 SQLHSTMT stmt;
03660 char sql[PATH_MAX];
03661 char msgnums[20];
03662 char *argv[] = { NULL, msgnums };
03663 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03664 struct odbc_obj *obj;
03665
03666 argv[0] = ast_strdupa(sdir);
03667
03668 obj = ast_odbc_request_obj(odbc_database, 0);
03669 if (obj) {
03670 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03671 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03672 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03673 if (!stmt)
03674 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03675 else
03676 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03677 ast_odbc_release_obj(obj);
03678 } else
03679 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03680 return;
03681 }
03682
03683
03684
03685
03686
03687
03688
03689
03690
03691
03692
03693
03694 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03695 {
03696 SQLHSTMT stmt;
03697 char sql[512];
03698 char msgnums[20];
03699 char msgnumd[20];
03700 struct odbc_obj *obj;
03701 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03702 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03703
03704 delete_file(ddir, dmsg);
03705 obj = ast_odbc_request_obj(odbc_database, 0);
03706 if (obj) {
03707 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03708 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03709 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);
03710 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03711 if (!stmt)
03712 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03713 else
03714 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03715 ast_odbc_release_obj(obj);
03716 } else
03717 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03718 return;
03719 }
03720
03721 struct insert_data {
03722 char *sql;
03723 const char *dir;
03724 const char *msgnums;
03725 void *data;
03726 SQLLEN datalen;
03727 SQLLEN indlen;
03728 const char *context;
03729 const char *macrocontext;
03730 const char *callerid;
03731 const char *origtime;
03732 const char *duration;
03733 const char *mailboxuser;
03734 const char *mailboxcontext;
03735 const char *category;
03736 const char *flag;
03737 };
03738
03739 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03740 {
03741 struct insert_data *data = vdata;
03742 int res;
03743 SQLHSTMT stmt;
03744
03745 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03746 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03747 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03748 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03749 return NULL;
03750 }
03751
03752 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03753 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03754 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03755 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03756 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03757 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03758 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03759 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03760 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03761 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03762 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03763 if (!ast_strlen_zero(data->category)) {
03764 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03765 }
03766 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03767 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03768 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03769 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03770 return NULL;
03771 }
03772
03773 return stmt;
03774 }
03775
03776
03777
03778
03779
03780
03781
03782
03783
03784
03785
03786
03787
03788
03789 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03790 {
03791 int res = 0;
03792 int fd = -1;
03793 void *fdm = MAP_FAILED;
03794 size_t fdlen = -1;
03795 SQLHSTMT stmt;
03796 char sql[PATH_MAX];
03797 char msgnums[20];
03798 char fn[PATH_MAX];
03799 char full_fn[PATH_MAX];
03800 char fmt[80]="";
03801 char *c;
03802 struct ast_config *cfg = NULL;
03803 struct odbc_obj *obj;
03804 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03805 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03806 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03807
03808 delete_file(dir, msgnum);
03809 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03810 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03811 return -1;
03812 }
03813
03814 do {
03815 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03816 c = strchr(fmt, '|');
03817 if (c)
03818 *c = '\0';
03819 if (!strcasecmp(fmt, "wav49"))
03820 strcpy(fmt, "WAV");
03821 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03822 if (msgnum > -1)
03823 make_file(fn, sizeof(fn), dir, msgnum);
03824 else
03825 ast_copy_string(fn, dir, sizeof(fn));
03826 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03827 cfg = ast_config_load(full_fn, config_flags);
03828 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03829 fd = open(full_fn, O_RDWR);
03830 if (fd < 0) {
03831 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03832 res = -1;
03833 break;
03834 }
03835 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03836 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03837 idata.context = "";
03838 }
03839 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03840 idata.macrocontext = "";
03841 }
03842 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03843 idata.callerid = "";
03844 }
03845 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03846 idata.origtime = "";
03847 }
03848 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03849 idata.duration = "";
03850 }
03851 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03852 idata.category = "";
03853 }
03854 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03855 idata.flag = "";
03856 }
03857 }
03858 fdlen = lseek(fd, 0, SEEK_END);
03859 lseek(fd, 0, SEEK_SET);
03860 printf("Length is %zd\n", fdlen);
03861 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03862 if (fdm == MAP_FAILED) {
03863 ast_log(AST_LOG_WARNING, "Memory map failed!\n");
03864 res = -1;
03865 break;
03866 }
03867 idata.data = fdm;
03868 idata.datalen = idata.indlen = fdlen;
03869
03870 if (!ast_strlen_zero(idata.category))
03871 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03872 else
03873 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03874
03875 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03876 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03877 } else {
03878 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03879 res = -1;
03880 }
03881 } while (0);
03882 if (obj) {
03883 ast_odbc_release_obj(obj);
03884 }
03885 if (cfg)
03886 ast_config_destroy(cfg);
03887 if (fdm != MAP_FAILED)
03888 munmap(fdm, fdlen);
03889 if (fd > -1)
03890 close(fd);
03891 return res;
03892 }
03893
03894
03895
03896
03897
03898
03899
03900
03901
03902
03903
03904
03905
03906
03907 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03908 {
03909 SQLHSTMT stmt;
03910 char sql[PATH_MAX];
03911 char msgnums[20];
03912 char msgnumd[20];
03913 struct odbc_obj *obj;
03914 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03915 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03916
03917 delete_file(ddir, dmsg);
03918 obj = ast_odbc_request_obj(odbc_database, 0);
03919 if (obj) {
03920 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03921 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03922 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03923 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03924 if (!stmt)
03925 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03926 else
03927 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03928 ast_odbc_release_obj(obj);
03929 } else
03930 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03931 return;
03932 }
03933
03934
03935
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945 static int remove_file(char *dir, int msgnum)
03946 {
03947 char fn[PATH_MAX];
03948 char full_fn[PATH_MAX];
03949 char msgnums[80];
03950
03951 if (msgnum > -1) {
03952 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03953 make_file(fn, sizeof(fn), dir, msgnum);
03954 } else
03955 ast_copy_string(fn, dir, sizeof(fn));
03956 ast_filedelete(fn, NULL);
03957 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03958 unlink(full_fn);
03959 return 0;
03960 }
03961 #else
03962 #ifndef IMAP_STORAGE
03963
03964
03965
03966
03967
03968
03969
03970
03971
03972 static int count_messages(struct ast_vm_user *vmu, char *dir)
03973 {
03974
03975 int vmcount = 0;
03976 DIR *vmdir = NULL;
03977 struct dirent *vment = NULL;
03978
03979 if (vm_lock_path(dir))
03980 return ERROR_LOCK_PATH;
03981
03982 if ((vmdir = opendir(dir))) {
03983 while ((vment = readdir(vmdir))) {
03984 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03985 vmcount++;
03986 }
03987 }
03988 closedir(vmdir);
03989 }
03990 ast_unlock_path(dir);
03991
03992 return vmcount;
03993 }
03994
03995
03996
03997
03998
03999
04000
04001
04002 static void rename_file(char *sfn, char *dfn)
04003 {
04004 char stxt[PATH_MAX];
04005 char dtxt[PATH_MAX];
04006 ast_filerename(sfn, dfn, NULL);
04007 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04008 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04009 if (ast_check_realtime("voicemail_data")) {
04010 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04011 }
04012 rename(stxt, dtxt);
04013 }
04014
04015
04016
04017
04018
04019
04020
04021
04022
04023
04024
04025
04026 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04027 {
04028 int x;
04029 unsigned char map[MAXMSGLIMIT] = "";
04030 DIR *msgdir;
04031 struct dirent *msgdirent;
04032 int msgdirint;
04033 char extension[4];
04034 int stopcount = 0;
04035
04036
04037
04038
04039
04040 if (!(msgdir = opendir(dir))) {
04041 return -1;
04042 }
04043
04044 while ((msgdirent = readdir(msgdir))) {
04045 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04046 map[msgdirint] = 1;
04047 stopcount++;
04048 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04049 }
04050 }
04051 closedir(msgdir);
04052
04053 for (x = 0; x < vmu->maxmsg; x++) {
04054 if (map[x] == 1) {
04055 stopcount--;
04056 } else if (map[x] == 0 && !stopcount) {
04057 break;
04058 }
04059 }
04060
04061 return x - 1;
04062 }
04063
04064 #endif
04065 #endif
04066 #ifndef IMAP_STORAGE
04067
04068
04069
04070
04071
04072
04073
04074
04075
04076
04077 static int copy(char *infile, char *outfile)
04078 {
04079 int ifd;
04080 int ofd;
04081 int res;
04082 int len;
04083 char buf[4096];
04084
04085 #ifdef HARDLINK_WHEN_POSSIBLE
04086
04087 if (link(infile, outfile)) {
04088 #endif
04089 if ((ifd = open(infile, O_RDONLY)) < 0) {
04090 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04091 return -1;
04092 }
04093 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04094 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04095 close(ifd);
04096 return -1;
04097 }
04098 do {
04099 len = read(ifd, buf, sizeof(buf));
04100 if (len < 0) {
04101 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04102 close(ifd);
04103 close(ofd);
04104 unlink(outfile);
04105 }
04106 if (len) {
04107 res = write(ofd, buf, len);
04108 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04109 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04110 close(ifd);
04111 close(ofd);
04112 unlink(outfile);
04113 }
04114 }
04115 } while (len);
04116 close(ifd);
04117 close(ofd);
04118 return 0;
04119 #ifdef HARDLINK_WHEN_POSSIBLE
04120 } else {
04121
04122 return 0;
04123 }
04124 #endif
04125 }
04126
04127
04128
04129
04130
04131
04132
04133
04134
04135
04136 static void copy_plain_file(char *frompath, char *topath)
04137 {
04138 char frompath2[PATH_MAX], topath2[PATH_MAX];
04139 struct ast_variable *tmp,*var = NULL;
04140 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04141 ast_filecopy(frompath, topath, NULL);
04142 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04143 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04144 if (ast_check_realtime("voicemail_data")) {
04145 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04146
04147 for (tmp = var; tmp; tmp = tmp->next) {
04148 if (!strcasecmp(tmp->name, "origmailbox")) {
04149 origmailbox = tmp->value;
04150 } else if (!strcasecmp(tmp->name, "context")) {
04151 context = tmp->value;
04152 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04153 macrocontext = tmp->value;
04154 } else if (!strcasecmp(tmp->name, "exten")) {
04155 exten = tmp->value;
04156 } else if (!strcasecmp(tmp->name, "priority")) {
04157 priority = tmp->value;
04158 } else if (!strcasecmp(tmp->name, "callerchan")) {
04159 callerchan = tmp->value;
04160 } else if (!strcasecmp(tmp->name, "callerid")) {
04161 callerid = tmp->value;
04162 } else if (!strcasecmp(tmp->name, "origdate")) {
04163 origdate = tmp->value;
04164 } else if (!strcasecmp(tmp->name, "origtime")) {
04165 origtime = tmp->value;
04166 } else if (!strcasecmp(tmp->name, "category")) {
04167 category = tmp->value;
04168 } else if (!strcasecmp(tmp->name, "duration")) {
04169 duration = tmp->value;
04170 }
04171 }
04172 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);
04173 }
04174 copy(frompath2, topath2);
04175 ast_variables_destroy(var);
04176 }
04177 #endif
04178
04179
04180
04181
04182
04183
04184
04185
04186
04187 static int vm_delete(char *file)
04188 {
04189 char *txt;
04190 int txtsize = 0;
04191
04192 txtsize = (strlen(file) + 5)*sizeof(char);
04193 txt = alloca(txtsize);
04194
04195
04196
04197 if (ast_check_realtime("voicemail_data")) {
04198 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04199 }
04200 snprintf(txt, txtsize, "%s.txt", file);
04201 unlink(txt);
04202 return ast_filedelete(file, NULL);
04203 }
04204
04205
04206
04207
04208 static int inbuf(struct baseio *bio, FILE *fi)
04209 {
04210 int l;
04211
04212 if (bio->ateof)
04213 return 0;
04214
04215 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04216 if (ferror(fi))
04217 return -1;
04218
04219 bio->ateof = 1;
04220 return 0;
04221 }
04222
04223 bio->iolen = l;
04224 bio->iocp = 0;
04225
04226 return 1;
04227 }
04228
04229
04230
04231
04232 static int inchar(struct baseio *bio, FILE *fi)
04233 {
04234 if (bio->iocp>=bio->iolen) {
04235 if (!inbuf(bio, fi))
04236 return EOF;
04237 }
04238
04239 return bio->iobuf[bio->iocp++];
04240 }
04241
04242
04243
04244
04245 static int ochar(struct baseio *bio, int c, FILE *so)
04246 {
04247 if (bio->linelength >= BASELINELEN) {
04248 if (fputs(ENDL, so) == EOF) {
04249 return -1;
04250 }
04251
04252 bio->linelength = 0;
04253 }
04254
04255 if (putc(((unsigned char) c), so) == EOF) {
04256 return -1;
04257 }
04258
04259 bio->linelength++;
04260
04261 return 1;
04262 }
04263
04264
04265
04266
04267
04268
04269
04270
04271
04272
04273 static int base_encode(char *filename, FILE *so)
04274 {
04275 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04276 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04277 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04278 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04279 int i, hiteof = 0;
04280 FILE *fi;
04281 struct baseio bio;
04282
04283 memset(&bio, 0, sizeof(bio));
04284 bio.iocp = BASEMAXINLINE;
04285
04286 if (!(fi = fopen(filename, "rb"))) {
04287 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04288 return -1;
04289 }
04290
04291 while (!hiteof){
04292 unsigned char igroup[3], ogroup[4];
04293 int c, n;
04294
04295 memset(igroup, 0, sizeof(igroup));
04296
04297 for (n = 0; n < 3; n++) {
04298 if ((c = inchar(&bio, fi)) == EOF) {
04299 hiteof = 1;
04300 break;
04301 }
04302
04303 igroup[n] = (unsigned char) c;
04304 }
04305
04306 if (n > 0) {
04307 ogroup[0]= dtable[igroup[0] >> 2];
04308 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04309 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04310 ogroup[3]= dtable[igroup[2] & 0x3F];
04311
04312 if (n < 3) {
04313 ogroup[3] = '=';
04314
04315 if (n < 2)
04316 ogroup[2] = '=';
04317 }
04318
04319 for (i = 0; i < 4; i++)
04320 ochar(&bio, ogroup[i], so);
04321 }
04322 }
04323
04324 fclose(fi);
04325
04326 if (fputs(ENDL, so) == EOF) {
04327 return 0;
04328 }
04329
04330 return 1;
04331 }
04332
04333 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)
04334 {
04335 char callerid[256];
04336 char num[12];
04337 char fromdir[256], fromfile[256];
04338 struct ast_config *msg_cfg;
04339 const char *origcallerid, *origtime;
04340 char origcidname[80], origcidnum[80], origdate[80];
04341 int inttime;
04342 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04343
04344
04345 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04346 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04347 snprintf(num, sizeof(num), "%d", msgnum);
04348 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04349 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04350 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04351 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04352 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04353 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04354 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04355 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04356 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04357 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04358
04359
04360 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04361 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04362 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04363 strcat(fromfile, ".txt");
04364 }
04365 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04366 if (option_debug > 0) {
04367 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04368 }
04369 return;
04370 }
04371
04372 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04373 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04374 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04375 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04376 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04377 }
04378
04379 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04380 struct timeval tv = { inttime, };
04381 struct ast_tm tm;
04382 ast_localtime(&tv, &tm, NULL);
04383 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04384 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04385 }
04386 ast_config_destroy(msg_cfg);
04387 }
04388
04389
04390
04391
04392
04393
04394
04395
04396
04397 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04398 {
04399 const char *ptr;
04400
04401
04402 ast_str_set(buf, maxlen, "\"");
04403 for (ptr = from; *ptr; ptr++) {
04404 if (*ptr == '"' || *ptr == '\\') {
04405 ast_str_append(buf, maxlen, "\\%c", *ptr);
04406 } else {
04407 ast_str_append(buf, maxlen, "%c", *ptr);
04408 }
04409 }
04410 ast_str_append(buf, maxlen, "\"");
04411
04412 return ast_str_buffer(*buf);
04413 }
04414
04415
04416
04417
04418
04419 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04420 {
04421 const struct vm_zone *z = NULL;
04422 struct timeval t = ast_tvnow();
04423
04424
04425 if (!ast_strlen_zero(vmu->zonetag)) {
04426
04427 AST_LIST_LOCK(&zones);
04428 AST_LIST_TRAVERSE(&zones, z, list) {
04429 if (!strcmp(z->name, vmu->zonetag))
04430 break;
04431 }
04432 AST_LIST_UNLOCK(&zones);
04433 }
04434 ast_localtime(&t, tm, z ? z->timezone : NULL);
04435 return tm;
04436 }
04437
04438
04439
04440
04441
04442 static int check_mime(const char *str)
04443 {
04444 for (; *str; str++) {
04445 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04446 return 1;
04447 }
04448 }
04449 return 0;
04450 }
04451
04452
04453
04454
04455
04456
04457
04458
04459
04460
04461
04462
04463
04464
04465
04466
04467
04468
04469 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04470 {
04471 struct ast_str *tmp = ast_str_alloca(80);
04472 int first_section = 1;
04473
04474 ast_str_reset(*end);
04475 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04476 for (; *start; start++) {
04477 int need_encoding = 0;
04478 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04479 need_encoding = 1;
04480 }
04481 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04482 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04483 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04484 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04485
04486 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04487 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04488 first_section = 0;
04489 }
04490 if (need_encoding && *start == ' ') {
04491 ast_str_append(&tmp, -1, "_");
04492 } else if (need_encoding) {
04493 ast_str_append(&tmp, -1, "=%hhX", *start);
04494 } else {
04495 ast_str_append(&tmp, -1, "%c", *start);
04496 }
04497 }
04498 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04499 return ast_str_buffer(*end);
04500 }
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525 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)
04526 {
04527 char date[256];
04528 char host[MAXHOSTNAMELEN] = "";
04529 char who[256];
04530 char bound[256];
04531 char dur[256];
04532 struct ast_tm tm;
04533 char enc_cidnum[256] = "", enc_cidname[256] = "";
04534 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04535 char *greeting_attachment;
04536 char filename[256];
04537
04538 if (!str1 || !str2) {
04539 ast_free(str1);
04540 ast_free(str2);
04541 return;
04542 }
04543
04544 if (cidnum) {
04545 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04546 }
04547 if (cidname) {
04548 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04549 }
04550 gethostname(host, sizeof(host) - 1);
04551
04552 if (strchr(srcemail, '@')) {
04553 ast_copy_string(who, srcemail, sizeof(who));
04554 } else {
04555 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04556 }
04557
04558 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04559 if (greeting_attachment) {
04560 *greeting_attachment++ = '\0';
04561 }
04562
04563 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04564 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04565 fprintf(p, "Date: %s" ENDL, date);
04566
04567
04568 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04569
04570 if (!ast_strlen_zero(fromstring)) {
04571 struct ast_channel *ast;
04572 if ((ast = ast_dummy_channel_alloc())) {
04573 char *ptr;
04574 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04575 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04576
04577 if (check_mime(ast_str_buffer(str1))) {
04578 int first_line = 1;
04579 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04580 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04581 *ptr = '\0';
04582 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04583 first_line = 0;
04584
04585 ast_str_set(&str2, 0, "%s", ptr + 1);
04586 }
04587 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04588 } else {
04589 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04590 }
04591 ast = ast_channel_unref(ast);
04592 } else {
04593 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04594 }
04595 } else {
04596 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04597 }
04598
04599 if (check_mime(vmu->fullname)) {
04600 int first_line = 1;
04601 char *ptr;
04602 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04603 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04604 *ptr = '\0';
04605 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04606 first_line = 0;
04607
04608 ast_str_set(&str2, 0, "%s", ptr + 1);
04609 }
04610 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04611 } else {
04612 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04613 }
04614
04615 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04616 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04617 struct ast_channel *ast;
04618 if ((ast = ast_dummy_channel_alloc())) {
04619 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04620 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04621 if (check_mime(ast_str_buffer(str1))) {
04622 int first_line = 1;
04623 char *ptr;
04624 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04625 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04626 *ptr = '\0';
04627 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04628 first_line = 0;
04629
04630 ast_str_set(&str2, 0, "%s", ptr + 1);
04631 }
04632 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04633 } else {
04634 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04635 }
04636 ast = ast_channel_unref(ast);
04637 } else {
04638 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04639 }
04640 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04641 if (ast_strlen_zero(flag)) {
04642 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04643 } else {
04644 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04645 }
04646 } else {
04647 if (ast_strlen_zero(flag)) {
04648 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04649 } else {
04650 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04651 }
04652 }
04653
04654 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04655 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04656 if (imap) {
04657
04658 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04659
04660 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04661 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04662 #ifdef IMAP_STORAGE
04663 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04664 #else
04665 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04666 #endif
04667
04668 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04669 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04670 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04671 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04672 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04673 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04674 if (!ast_strlen_zero(category)) {
04675 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04676 } else {
04677 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04678 }
04679 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04680 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04681 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04682 }
04683 if (!ast_strlen_zero(cidnum)) {
04684 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04685 }
04686 if (!ast_strlen_zero(cidname)) {
04687 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04688 }
04689 fprintf(p, "MIME-Version: 1.0" ENDL);
04690 if (attach_user_voicemail) {
04691
04692 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04693 (int) getpid(), (unsigned int) ast_random());
04694
04695 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04696 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04697 fprintf(p, "--%s" ENDL, bound);
04698 }
04699 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04700 if (emailbody || vmu->emailbody) {
04701 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04702 struct ast_channel *ast;
04703 if ((ast = ast_dummy_channel_alloc())) {
04704 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04705 ast_str_substitute_variables(&str1, 0, ast, e_body);
04706 #ifdef IMAP_STORAGE
04707 {
04708
04709 char *line = ast_str_buffer(str1), *next;
04710 do {
04711
04712 if ((next = strchr(line, '\n'))) {
04713 *next++ = '\0';
04714 }
04715 fprintf(p, "%s" ENDL, line);
04716 line = next;
04717 } while (!ast_strlen_zero(line));
04718 }
04719 #else
04720 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04721 #endif
04722 ast = ast_channel_unref(ast);
04723 } else {
04724 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04725 }
04726 } else if (msgnum > -1) {
04727 if (strcmp(vmu->mailbox, mailbox)) {
04728
04729 struct ast_config *msg_cfg;
04730 const char *v;
04731 int inttime;
04732 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04733 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04734
04735 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04736 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04737 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04738 strcat(fromfile, ".txt");
04739 }
04740 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04741 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04742 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04743 }
04744
04745
04746
04747 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04748 struct timeval tv = { inttime, };
04749 struct ast_tm tm;
04750 ast_localtime(&tv, &tm, NULL);
04751 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04752 }
04753 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04754 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04755 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04756 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04757 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04758 date, origcallerid, origdate);
04759 ast_config_destroy(msg_cfg);
04760 } else {
04761 goto plain_message;
04762 }
04763 } else {
04764 plain_message:
04765 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04766 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04767 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04768 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04769 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04770 }
04771 } else {
04772 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04773 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04774 }
04775
04776 if (imap || attach_user_voicemail) {
04777 if (!ast_strlen_zero(attach2)) {
04778 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04779 ast_debug(5, "creating second attachment filename %s\n", filename);
04780 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04781 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04782 ast_debug(5, "creating attachment filename %s\n", filename);
04783 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04784 } else {
04785 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04786 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04787 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04788 }
04789 }
04790 ast_free(str1);
04791 ast_free(str2);
04792 }
04793
04794 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)
04795 {
04796 char tmpdir[256], newtmp[256];
04797 char fname[256];
04798 char tmpcmd[256];
04799 int tmpfd = -1;
04800 int soxstatus = 0;
04801
04802
04803 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04804
04805 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04806 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04807 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04808 tmpfd = mkstemp(newtmp);
04809 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04810 ast_debug(3, "newtmp: %s\n", newtmp);
04811 if (tmpfd > -1) {
04812 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04813 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04814 attach = newtmp;
04815 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04816 } else {
04817 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04818 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04819 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04820 }
04821 }
04822 }
04823 fprintf(p, "--%s" ENDL, bound);
04824 if (msgnum > -1)
04825 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04826 else
04827 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04828 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04829 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04830 if (msgnum > -1)
04831 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04832 else
04833 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04834 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04835 base_encode(fname, p);
04836 if (last)
04837 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04838 if (tmpfd > -1) {
04839 if (soxstatus == 0) {
04840 unlink(fname);
04841 }
04842 close(tmpfd);
04843 unlink(newtmp);
04844 }
04845 return 0;
04846 }
04847
04848 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)
04849 {
04850 FILE *p = NULL;
04851 char tmp[80] = "/tmp/astmail-XXXXXX";
04852 char tmp2[256];
04853 char *stringp;
04854
04855 if (vmu && ast_strlen_zero(vmu->email)) {
04856 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04857 return(0);
04858 }
04859
04860
04861 format = ast_strdupa(format);
04862 stringp = format;
04863 strsep(&stringp, "|");
04864
04865 if (!strcmp(format, "wav49"))
04866 format = "WAV";
04867 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));
04868
04869
04870 if ((p = vm_mkftemp(tmp)) == NULL) {
04871 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04872 return -1;
04873 } else {
04874 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04875 fclose(p);
04876 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04877 ast_safe_system(tmp2);
04878 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04879 }
04880 return 0;
04881 }
04882
04883 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)
04884 {
04885 char enc_cidnum[256], enc_cidname[256];
04886 char date[256];
04887 char host[MAXHOSTNAMELEN] = "";
04888 char who[256];
04889 char dur[PATH_MAX];
04890 char tmp[80] = "/tmp/astmail-XXXXXX";
04891 char tmp2[PATH_MAX];
04892 struct ast_tm tm;
04893 FILE *p;
04894 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04895
04896 if (!str1 || !str2) {
04897 ast_free(str1);
04898 ast_free(str2);
04899 return -1;
04900 }
04901
04902 if (cidnum) {
04903 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04904 }
04905 if (cidname) {
04906 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04907 }
04908
04909 if ((p = vm_mkftemp(tmp)) == NULL) {
04910 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04911 ast_free(str1);
04912 ast_free(str2);
04913 return -1;
04914 }
04915 gethostname(host, sizeof(host)-1);
04916 if (strchr(srcemail, '@')) {
04917 ast_copy_string(who, srcemail, sizeof(who));
04918 } else {
04919 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04920 }
04921 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04922 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04923 fprintf(p, "Date: %s\n", date);
04924
04925
04926 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04927
04928 if (!ast_strlen_zero(pagerfromstring)) {
04929 struct ast_channel *ast;
04930 if ((ast = ast_dummy_channel_alloc())) {
04931 char *ptr;
04932 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04933 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04934
04935 if (check_mime(ast_str_buffer(str1))) {
04936 int first_line = 1;
04937 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04938 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04939 *ptr = '\0';
04940 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04941 first_line = 0;
04942
04943 ast_str_set(&str2, 0, "%s", ptr + 1);
04944 }
04945 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04946 } else {
04947 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04948 }
04949 ast = ast_channel_unref(ast);
04950 } else {
04951 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04952 }
04953 } else {
04954 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04955 }
04956
04957 if (check_mime(vmu->fullname)) {
04958 int first_line = 1;
04959 char *ptr;
04960 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04961 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04962 *ptr = '\0';
04963 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04964 first_line = 0;
04965
04966 ast_str_set(&str2, 0, "%s", ptr + 1);
04967 }
04968 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04969 } else {
04970 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04971 }
04972
04973 if (!ast_strlen_zero(pagersubject)) {
04974 struct ast_channel *ast;
04975 if ((ast = ast_dummy_channel_alloc())) {
04976 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04977 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04978 if (check_mime(ast_str_buffer(str1))) {
04979 int first_line = 1;
04980 char *ptr;
04981 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04982 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04983 *ptr = '\0';
04984 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04985 first_line = 0;
04986
04987 ast_str_set(&str2, 0, "%s", ptr + 1);
04988 }
04989 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04990 } else {
04991 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04992 }
04993 ast = ast_channel_unref(ast);
04994 } else {
04995 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04996 }
04997 } else {
04998 if (ast_strlen_zero(flag)) {
04999 fprintf(p, "Subject: New VM\n\n");
05000 } else {
05001 fprintf(p, "Subject: New %s VM\n\n", flag);
05002 }
05003 }
05004
05005 if (pagerbody) {
05006 struct ast_channel *ast;
05007 if ((ast = ast_dummy_channel_alloc())) {
05008 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05009 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05010 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05011 ast = ast_channel_unref(ast);
05012 } else {
05013 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05014 }
05015 } else {
05016 fprintf(p, "New %s long %s msg in box %s\n"
05017 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05018 }
05019
05020 fclose(p);
05021 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05022 ast_safe_system(tmp2);
05023 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05024 ast_free(str1);
05025 ast_free(str2);
05026 return 0;
05027 }
05028
05029
05030
05031
05032
05033
05034
05035
05036
05037
05038 static int get_date(char *s, int len)
05039 {
05040 struct ast_tm tm;
05041 struct timeval t = ast_tvnow();
05042
05043 ast_localtime(&t, &tm, "UTC");
05044
05045 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05046 }
05047
05048 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05049 {
05050 int res;
05051 char fn[PATH_MAX];
05052 char dest[PATH_MAX];
05053
05054 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05055
05056 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05057 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05058 return -1;
05059 }
05060
05061 RETRIEVE(fn, -1, ext, context);
05062 if (ast_fileexists(fn, NULL, NULL) > 0) {
05063 res = ast_stream_and_wait(chan, fn, ecodes);
05064 if (res) {
05065 DISPOSE(fn, -1);
05066 return res;
05067 }
05068 } else {
05069
05070 DISPOSE(fn, -1);
05071 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05072 if (res)
05073 return res;
05074 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05075 if (res)
05076 return res;
05077 }
05078 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05079 return res;
05080 }
05081
05082 static void free_zone(struct vm_zone *z)
05083 {
05084 ast_free(z);
05085 }
05086
05087 #ifdef ODBC_STORAGE
05088 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05089 {
05090 int x = -1;
05091 int res;
05092 SQLHSTMT stmt = NULL;
05093 char sql[PATH_MAX];
05094 char rowdata[20];
05095 char tmp[PATH_MAX] = "";
05096 struct odbc_obj *obj = NULL;
05097 char *context;
05098 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05099
05100 if (newmsgs)
05101 *newmsgs = 0;
05102 if (oldmsgs)
05103 *oldmsgs = 0;
05104 if (urgentmsgs)
05105 *urgentmsgs = 0;
05106
05107
05108 if (ast_strlen_zero(mailbox))
05109 return 0;
05110
05111 ast_copy_string(tmp, mailbox, sizeof(tmp));
05112
05113 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05114 int u, n, o;
05115 char *next, *remaining = tmp;
05116 while ((next = strsep(&remaining, " ,"))) {
05117 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05118 return -1;
05119 }
05120 if (urgentmsgs) {
05121 *urgentmsgs += u;
05122 }
05123 if (newmsgs) {
05124 *newmsgs += n;
05125 }
05126 if (oldmsgs) {
05127 *oldmsgs += o;
05128 }
05129 }
05130 return 0;
05131 }
05132
05133 context = strchr(tmp, '@');
05134 if (context) {
05135 *context = '\0';
05136 context++;
05137 } else
05138 context = "default";
05139
05140 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05141 do {
05142 if (newmsgs) {
05143 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05144 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05145 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05146 break;
05147 }
05148 res = SQLFetch(stmt);
05149 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05150 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05151 break;
05152 }
05153 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05154 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05155 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05156 break;
05157 }
05158 *newmsgs = atoi(rowdata);
05159 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05160 }
05161
05162 if (oldmsgs) {
05163 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05164 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05165 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05166 break;
05167 }
05168 res = SQLFetch(stmt);
05169 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05170 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05171 break;
05172 }
05173 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05174 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05175 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05176 break;
05177 }
05178 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05179 *oldmsgs = atoi(rowdata);
05180 }
05181
05182 if (urgentmsgs) {
05183 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05184 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05185 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05186 break;
05187 }
05188 res = SQLFetch(stmt);
05189 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05190 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05191 break;
05192 }
05193 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05194 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05195 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05196 break;
05197 }
05198 *urgentmsgs = atoi(rowdata);
05199 }
05200
05201 x = 0;
05202 } while (0);
05203 } else {
05204 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05205 }
05206
05207 if (stmt) {
05208 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05209 }
05210 if (obj) {
05211 ast_odbc_release_obj(obj);
05212 }
05213 return x;
05214 }
05215
05216
05217
05218
05219
05220
05221
05222
05223
05224
05225 static int messagecount(const char *context, const char *mailbox, const char *folder)
05226 {
05227 struct odbc_obj *obj = NULL;
05228 int nummsgs = 0;
05229 int res;
05230 SQLHSTMT stmt = NULL;
05231 char sql[PATH_MAX];
05232 char rowdata[20];
05233 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05234 if (!folder)
05235 folder = "INBOX";
05236
05237 if (ast_strlen_zero(mailbox))
05238 return 0;
05239
05240 obj = ast_odbc_request_obj(odbc_database, 0);
05241 if (obj) {
05242 if (!strcmp(folder, "INBOX")) {
05243 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);
05244 } else {
05245 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05246 }
05247 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05248 if (!stmt) {
05249 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05250 goto yuck;
05251 }
05252 res = SQLFetch(stmt);
05253 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05254 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05255 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05256 goto yuck;
05257 }
05258 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05259 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05260 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05261 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05262 goto yuck;
05263 }
05264 nummsgs = atoi(rowdata);
05265 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05266 } else
05267 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05268
05269 yuck:
05270 if (obj)
05271 ast_odbc_release_obj(obj);
05272 return nummsgs;
05273 }
05274
05275
05276
05277
05278
05279
05280
05281
05282
05283 static int has_voicemail(const char *mailbox, const char *folder)
05284 {
05285 char tmp[256], *tmp2 = tmp, *box, *context;
05286 ast_copy_string(tmp, mailbox, sizeof(tmp));
05287 while ((context = box = strsep(&tmp2, ",&"))) {
05288 strsep(&context, "@");
05289 if (ast_strlen_zero(context))
05290 context = "default";
05291 if (messagecount(context, box, folder))
05292 return 1;
05293 }
05294 return 0;
05295 }
05296 #endif
05297 #ifndef IMAP_STORAGE
05298
05299
05300
05301
05302
05303
05304
05305
05306
05307
05308
05309
05310
05311
05312
05313
05314 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)
05315 {
05316 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05317 const char *frombox = mbox(vmu, imbox);
05318 const char *userfolder;
05319 int recipmsgnum;
05320 int res = 0;
05321
05322 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05323
05324 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05325 userfolder = "Urgent";
05326 } else {
05327 userfolder = "INBOX";
05328 }
05329
05330 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05331
05332 if (!dir)
05333 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05334 else
05335 ast_copy_string(fromdir, dir, sizeof(fromdir));
05336
05337 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05338 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05339
05340 if (vm_lock_path(todir))
05341 return ERROR_LOCK_PATH;
05342
05343 recipmsgnum = last_message_index(recip, todir) + 1;
05344 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05345 make_file(topath, sizeof(topath), todir, recipmsgnum);
05346 #ifndef ODBC_STORAGE
05347 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05348 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05349 } else {
05350 #endif
05351
05352
05353
05354 copy_plain_file(frompath, topath);
05355 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05356 vm_delete(topath);
05357 #ifndef ODBC_STORAGE
05358 }
05359 #endif
05360 } else {
05361 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05362 res = -1;
05363 }
05364 ast_unlock_path(todir);
05365 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05366 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05367 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05368 flag);
05369
05370 return res;
05371 }
05372 #endif
05373 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05374
05375 static int messagecount(const char *context, const char *mailbox, const char *folder)
05376 {
05377 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05378 }
05379
05380 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05381 {
05382 DIR *dir;
05383 struct dirent *de;
05384 char fn[256];
05385 int ret = 0;
05386
05387
05388 if (ast_strlen_zero(mailbox))
05389 return 0;
05390
05391 if (ast_strlen_zero(folder))
05392 folder = "INBOX";
05393 if (ast_strlen_zero(context))
05394 context = "default";
05395
05396 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05397
05398 if (!(dir = opendir(fn)))
05399 return 0;
05400
05401 while ((de = readdir(dir))) {
05402 if (!strncasecmp(de->d_name, "msg", 3)) {
05403 if (shortcircuit) {
05404 ret = 1;
05405 break;
05406 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05407 ret++;
05408 }
05409 }
05410 }
05411
05412 closedir(dir);
05413
05414 return ret;
05415 }
05416
05417
05418
05419
05420
05421
05422
05423
05424
05425
05426 static int has_voicemail(const char *mailbox, const char *folder)
05427 {
05428 char tmp[256], *tmp2 = tmp, *box, *context;
05429 ast_copy_string(tmp, mailbox, sizeof(tmp));
05430 if (ast_strlen_zero(folder)) {
05431 folder = "INBOX";
05432 }
05433 while ((box = strsep(&tmp2, ",&"))) {
05434 if ((context = strchr(box, '@')))
05435 *context++ = '\0';
05436 else
05437 context = "default";
05438 if (__has_voicemail(context, box, folder, 1))
05439 return 1;
05440
05441 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05442 return 1;
05443 }
05444 }
05445 return 0;
05446 }
05447
05448
05449 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05450 {
05451 char tmp[256];
05452 char *context;
05453
05454
05455 if (ast_strlen_zero(mailbox))
05456 return 0;
05457
05458 if (newmsgs)
05459 *newmsgs = 0;
05460 if (oldmsgs)
05461 *oldmsgs = 0;
05462 if (urgentmsgs)
05463 *urgentmsgs = 0;
05464
05465 if (strchr(mailbox, ',')) {
05466 int tmpnew, tmpold, tmpurgent;
05467 char *mb, *cur;
05468
05469 ast_copy_string(tmp, mailbox, sizeof(tmp));
05470 mb = tmp;
05471 while ((cur = strsep(&mb, ", "))) {
05472 if (!ast_strlen_zero(cur)) {
05473 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05474 return -1;
05475 else {
05476 if (newmsgs)
05477 *newmsgs += tmpnew;
05478 if (oldmsgs)
05479 *oldmsgs += tmpold;
05480 if (urgentmsgs)
05481 *urgentmsgs += tmpurgent;
05482 }
05483 }
05484 }
05485 return 0;
05486 }
05487
05488 ast_copy_string(tmp, mailbox, sizeof(tmp));
05489
05490 if ((context = strchr(tmp, '@')))
05491 *context++ = '\0';
05492 else
05493 context = "default";
05494
05495 if (newmsgs)
05496 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05497 if (oldmsgs)
05498 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05499 if (urgentmsgs)
05500 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05501
05502 return 0;
05503 }
05504
05505 #endif
05506
05507
05508 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05509 {
05510 int urgentmsgs = 0;
05511 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05512 if (newmsgs) {
05513 *newmsgs += urgentmsgs;
05514 }
05515 return res;
05516 }
05517
05518 static void run_externnotify(char *context, char *extension, const char *flag)
05519 {
05520 char arguments[255];
05521 char ext_context[256] = "";
05522 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05523 struct ast_smdi_mwi_message *mwi_msg;
05524
05525 if (!ast_strlen_zero(context))
05526 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05527 else
05528 ast_copy_string(ext_context, extension, sizeof(ext_context));
05529
05530 if (smdi_iface) {
05531 if (ast_app_has_voicemail(ext_context, NULL))
05532 ast_smdi_mwi_set(smdi_iface, extension);
05533 else
05534 ast_smdi_mwi_unset(smdi_iface, extension);
05535
05536 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05537 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05538 if (!strncmp(mwi_msg->cause, "INV", 3))
05539 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05540 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05541 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05542 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05543 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05544 } else {
05545 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05546 }
05547 }
05548
05549 if (!ast_strlen_zero(externnotify)) {
05550 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05551 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05552 } else {
05553 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05554 ast_debug(1, "Executing %s\n", arguments);
05555 ast_safe_system(arguments);
05556 }
05557 }
05558 }
05559
05560
05561
05562
05563
05564
05565 struct leave_vm_options {
05566 unsigned int flags;
05567 signed char record_gain;
05568 char *exitcontext;
05569 };
05570
05571
05572
05573
05574
05575
05576
05577
05578
05579
05580
05581 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05582 {
05583 #ifdef IMAP_STORAGE
05584 int newmsgs, oldmsgs;
05585 #else
05586 char urgdir[PATH_MAX];
05587 #endif
05588 char txtfile[PATH_MAX];
05589 char tmptxtfile[PATH_MAX];
05590 struct vm_state *vms = NULL;
05591 char callerid[256];
05592 FILE *txt;
05593 char date[256];
05594 int txtdes;
05595 int res = 0;
05596 int msgnum;
05597 int duration = 0;
05598 int sound_duration = 0;
05599 int ausemacro = 0;
05600 int ousemacro = 0;
05601 int ouseexten = 0;
05602 char tmpdur[16];
05603 char priority[16];
05604 char origtime[16];
05605 char dir[PATH_MAX];
05606 char tmpdir[PATH_MAX];
05607 char fn[PATH_MAX];
05608 char prefile[PATH_MAX] = "";
05609 char tempfile[PATH_MAX] = "";
05610 char ext_context[256] = "";
05611 char fmt[80];
05612 char *context;
05613 char ecodes[17] = "#";
05614 struct ast_str *tmp = ast_str_create(16);
05615 char *tmpptr;
05616 struct ast_vm_user *vmu;
05617 struct ast_vm_user svm;
05618 const char *category = NULL;
05619 const char *code;
05620 const char *alldtmf = "0123456789ABCD*#";
05621 char flag[80];
05622
05623 if (!tmp) {
05624 return -1;
05625 }
05626
05627 ast_str_set(&tmp, 0, "%s", ext);
05628 ext = ast_str_buffer(tmp);
05629 if ((context = strchr(ext, '@'))) {
05630 *context++ = '\0';
05631 tmpptr = strchr(context, '&');
05632 } else {
05633 tmpptr = strchr(ext, '&');
05634 }
05635
05636 if (tmpptr)
05637 *tmpptr++ = '\0';
05638
05639 ast_channel_lock(chan);
05640 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05641 category = ast_strdupa(category);
05642 }
05643 ast_channel_unlock(chan);
05644
05645 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05646 ast_copy_string(flag, "Urgent", sizeof(flag));
05647 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05648 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05649 } else {
05650 flag[0] = '\0';
05651 }
05652
05653 ast_debug(3, "Before find_user\n");
05654 if (!(vmu = find_user(&svm, context, ext))) {
05655 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05656 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05657 ast_free(tmp);
05658 return res;
05659 }
05660
05661 if (strcmp(vmu->context, "default"))
05662 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05663 else
05664 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05665
05666
05667
05668
05669
05670
05671 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05672 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05673 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05674 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05675 }
05676
05677
05678
05679
05680 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05681 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05682 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05683 ast_free(tmp);
05684 return -1;
05685 }
05686 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05687 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05688 ast_copy_string(prefile, tempfile, sizeof(prefile));
05689
05690 DISPOSE(tempfile, -1);
05691
05692 #ifndef IMAP_STORAGE
05693 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05694 #else
05695 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05696 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05697 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05698 }
05699 #endif
05700
05701
05702 if (ast_test_flag(vmu, VM_OPERATOR)) {
05703 if (!ast_strlen_zero(vmu->exit)) {
05704 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05705 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05706 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05707 ouseexten = 1;
05708 }
05709 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05710 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05711 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05712 ouseexten = 1;
05713 } else if (!ast_strlen_zero(chan->macrocontext)
05714 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05715 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05716 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05717 ousemacro = 1;
05718 }
05719 }
05720
05721 if (!ast_strlen_zero(vmu->exit)) {
05722 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05723 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05724 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05725 }
05726 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05727 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05728 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05729 } else if (!ast_strlen_zero(chan->macrocontext)
05730 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05731 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05732 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05733 ausemacro = 1;
05734 }
05735
05736 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05737 for (code = alldtmf; *code; code++) {
05738 char e[2] = "";
05739 e[0] = *code;
05740 if (strchr(ecodes, e[0]) == NULL
05741 && ast_canmatch_extension(chan, chan->context, e, 1,
05742 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05743 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05744 }
05745 }
05746 }
05747
05748
05749 if (!ast_strlen_zero(prefile)) {
05750 #ifdef ODBC_STORAGE
05751 int success =
05752 #endif
05753 RETRIEVE(prefile, -1, ext, context);
05754 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05755 if (ast_streamfile(chan, prefile, chan->language) > -1)
05756 res = ast_waitstream(chan, ecodes);
05757 #ifdef ODBC_STORAGE
05758 if (success == -1) {
05759
05760 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05761 store_file(prefile, vmu->mailbox, vmu->context, -1);
05762 }
05763 #endif
05764 } else {
05765 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05766 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05767 }
05768 DISPOSE(prefile, -1);
05769 if (res < 0) {
05770 ast_debug(1, "Hang up during prefile playback\n");
05771 free_user(vmu);
05772 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05773 ast_free(tmp);
05774 return -1;
05775 }
05776 }
05777 if (res == '#') {
05778
05779 ast_set_flag(options, OPT_SILENT);
05780 res = 0;
05781 }
05782
05783 if (vmu->maxmsg == 0) {
05784 if (option_debug > 2)
05785 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05786 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05787 goto leave_vm_out;
05788 }
05789 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05790 res = ast_stream_and_wait(chan, INTRO, ecodes);
05791 if (res == '#') {
05792 ast_set_flag(options, OPT_SILENT);
05793 res = 0;
05794 }
05795 }
05796 if (res > 0)
05797 ast_stopstream(chan);
05798
05799
05800 if (res == '*') {
05801 chan->exten[0] = 'a';
05802 chan->exten[1] = '\0';
05803 if (!ast_strlen_zero(vmu->exit)) {
05804 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05805 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05806 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05807 }
05808 chan->priority = 0;
05809 free_user(vmu);
05810 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05811 ast_free(tmp);
05812 return 0;
05813 }
05814
05815
05816 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05817 transfer:
05818 if (ouseexten || ousemacro) {
05819 chan->exten[0] = 'o';
05820 chan->exten[1] = '\0';
05821 if (!ast_strlen_zero(vmu->exit)) {
05822 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05823 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05824 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05825 }
05826 ast_play_and_wait(chan, "transfer");
05827 chan->priority = 0;
05828 free_user(vmu);
05829 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05830 }
05831 ast_free(tmp);
05832 return OPERATOR_EXIT;
05833 }
05834
05835
05836 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05837 if (!ast_strlen_zero(options->exitcontext))
05838 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05839 free_user(vmu);
05840 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05841 ast_free(tmp);
05842 return res;
05843 }
05844
05845 if (res < 0) {
05846 free_user(vmu);
05847 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05848 ast_free(tmp);
05849 return -1;
05850 }
05851
05852 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05853 if (!ast_strlen_zero(fmt)) {
05854 msgnum = 0;
05855
05856 #ifdef IMAP_STORAGE
05857
05858
05859 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05860 if (res < 0) {
05861 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05862 ast_free(tmp);
05863 return -1;
05864 }
05865 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05866
05867
05868
05869
05870 if (!(vms = create_vm_state_from_user(vmu))) {
05871 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05872 ast_free(tmp);
05873 return -1;
05874 }
05875 }
05876 vms->newmessages++;
05877
05878
05879 msgnum = newmsgs + oldmsgs;
05880 ast_debug(3, "Messagecount set to %d\n", msgnum);
05881 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05882
05883 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05884
05885 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05886 goto leave_vm_out;
05887 }
05888 #else
05889 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05890 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05891 if (!res)
05892 res = ast_waitstream(chan, "");
05893 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05894 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05895 inprocess_count(vmu->mailbox, vmu->context, -1);
05896 goto leave_vm_out;
05897 }
05898
05899 #endif
05900 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05901 txtdes = mkstemp(tmptxtfile);
05902 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05903 if (txtdes < 0) {
05904 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05905 if (!res)
05906 res = ast_waitstream(chan, "");
05907 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05908 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05909 inprocess_count(vmu->mailbox, vmu->context, -1);
05910 goto leave_vm_out;
05911 }
05912
05913
05914 if (res >= 0) {
05915
05916 res = ast_stream_and_wait(chan, "beep", "");
05917 }
05918
05919
05920 if (ast_check_realtime("voicemail_data")) {
05921 snprintf(priority, sizeof(priority), "%d", chan->priority);
05922 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05923 get_date(date, sizeof(date));
05924 ast_callerid_merge(callerid, sizeof(callerid),
05925 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05926 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05927 "Unknown");
05928 ast_store_realtime("voicemail_data",
05929 "origmailbox", ext,
05930 "context", chan->context,
05931 "macrocontext", chan->macrocontext,
05932 "exten", chan->exten,
05933 "priority", priority,
05934 "callerchan", chan->name,
05935 "callerid", callerid,
05936 "origdate", date,
05937 "origtime", origtime,
05938 "category", S_OR(category, ""),
05939 "filename", tmptxtfile,
05940 SENTINEL);
05941 }
05942
05943
05944 txt = fdopen(txtdes, "w+");
05945 if (txt) {
05946 get_date(date, sizeof(date));
05947 ast_callerid_merge(callerid, sizeof(callerid),
05948 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05949 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05950 "Unknown");
05951 fprintf(txt,
05952 ";\n"
05953 "; Message Information file\n"
05954 ";\n"
05955 "[message]\n"
05956 "origmailbox=%s\n"
05957 "context=%s\n"
05958 "macrocontext=%s\n"
05959 "exten=%s\n"
05960 "rdnis=%s\n"
05961 "priority=%d\n"
05962 "callerchan=%s\n"
05963 "callerid=%s\n"
05964 "origdate=%s\n"
05965 "origtime=%ld\n"
05966 "category=%s\n",
05967 ext,
05968 chan->context,
05969 chan->macrocontext,
05970 chan->exten,
05971 S_COR(chan->redirecting.from.number.valid,
05972 chan->redirecting.from.number.str, "unknown"),
05973 chan->priority,
05974 chan->name,
05975 callerid,
05976 date, (long) time(NULL),
05977 category ? category : "");
05978 } else {
05979 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05980 inprocess_count(vmu->mailbox, vmu->context, -1);
05981 if (ast_check_realtime("voicemail_data")) {
05982 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05983 }
05984 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05985 goto leave_vm_out;
05986 }
05987 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
05988
05989 if (txt) {
05990 fprintf(txt, "flag=%s\n", flag);
05991 if (sound_duration < vmu->minsecs) {
05992 fclose(txt);
05993 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
05994 ast_filedelete(tmptxtfile, NULL);
05995 unlink(tmptxtfile);
05996 if (ast_check_realtime("voicemail_data")) {
05997 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05998 }
05999 inprocess_count(vmu->mailbox, vmu->context, -1);
06000 } else {
06001 fprintf(txt, "duration=%d\n", duration);
06002 fclose(txt);
06003 if (vm_lock_path(dir)) {
06004 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06005
06006 ast_filedelete(tmptxtfile, NULL);
06007 unlink(tmptxtfile);
06008 inprocess_count(vmu->mailbox, vmu->context, -1);
06009 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06010 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06011 unlink(tmptxtfile);
06012 ast_unlock_path(dir);
06013 inprocess_count(vmu->mailbox, vmu->context, -1);
06014 if (ast_check_realtime("voicemail_data")) {
06015 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06016 }
06017 } else {
06018 #ifndef IMAP_STORAGE
06019 msgnum = last_message_index(vmu, dir) + 1;
06020 #endif
06021 make_file(fn, sizeof(fn), dir, msgnum);
06022
06023
06024 #ifndef IMAP_STORAGE
06025 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06026 #else
06027 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06028 #endif
06029
06030 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06031 ast_filerename(tmptxtfile, fn, NULL);
06032 rename(tmptxtfile, txtfile);
06033 inprocess_count(vmu->mailbox, vmu->context, -1);
06034
06035
06036
06037 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06038 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06039
06040 ast_unlock_path(dir);
06041 if (ast_check_realtime("voicemail_data")) {
06042 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06043 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06044 }
06045
06046
06047
06048 if (ast_fileexists(fn, NULL, NULL) > 0) {
06049 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06050 }
06051
06052
06053 while (tmpptr) {
06054 struct ast_vm_user recipu, *recip;
06055 char *exten, *cntx;
06056
06057 exten = strsep(&tmpptr, "&");
06058 cntx = strchr(exten, '@');
06059 if (cntx) {
06060 *cntx = '\0';
06061 cntx++;
06062 }
06063 if ((recip = find_user(&recipu, cntx, exten))) {
06064 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06065 free_user(recip);
06066 }
06067 }
06068 #ifndef IMAP_STORAGE
06069 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06070
06071 char sfn[PATH_MAX];
06072 char dfn[PATH_MAX];
06073 int x;
06074
06075 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06076 x = last_message_index(vmu, urgdir) + 1;
06077 make_file(sfn, sizeof(sfn), dir, msgnum);
06078 make_file(dfn, sizeof(dfn), urgdir, x);
06079 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06080 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06081
06082 ast_copy_string(fn, dfn, sizeof(fn));
06083 msgnum = x;
06084 }
06085 #endif
06086
06087 if (ast_fileexists(fn, NULL, NULL)) {
06088 #ifdef IMAP_STORAGE
06089 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06090 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06091 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06092 flag);
06093 #else
06094 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06095 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06096 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06097 flag);
06098 #endif
06099 }
06100
06101
06102 if (ast_fileexists(fn, NULL, NULL)) {
06103 DISPOSE(dir, msgnum);
06104 }
06105 }
06106 }
06107 } else {
06108 inprocess_count(vmu->mailbox, vmu->context, -1);
06109 }
06110 if (res == '0') {
06111 goto transfer;
06112 } else if (res > 0 && res != 't')
06113 res = 0;
06114
06115 if (sound_duration < vmu->minsecs)
06116
06117 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06118 else
06119 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06120 } else
06121 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06122 leave_vm_out:
06123 free_user(vmu);
06124
06125 #ifdef IMAP_STORAGE
06126
06127 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06128 if (expungeonhangup == 1) {
06129 ast_mutex_lock(&vms->lock);
06130 #ifdef HAVE_IMAP_TK2006
06131 if (LEVELUIDPLUS (vms->mailstream)) {
06132 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06133 } else
06134 #endif
06135 mail_expunge(vms->mailstream);
06136 ast_mutex_unlock(&vms->lock);
06137 }
06138 #endif
06139
06140 ast_free(tmp);
06141 return res;
06142 }
06143
06144 #if !defined(IMAP_STORAGE)
06145 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06146 {
06147
06148
06149 int x, dest;
06150 char sfn[PATH_MAX];
06151 char dfn[PATH_MAX];
06152
06153 if (vm_lock_path(dir)) {
06154 return ERROR_LOCK_PATH;
06155 }
06156
06157 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06158 make_file(sfn, sizeof(sfn), dir, x);
06159 if (EXISTS(dir, x, sfn, NULL)) {
06160
06161 if (x != dest) {
06162 make_file(dfn, sizeof(dfn), dir, dest);
06163 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06164 }
06165
06166 dest++;
06167 }
06168 }
06169 ast_unlock_path(dir);
06170
06171 return dest;
06172 }
06173 #endif
06174
06175 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06176 {
06177 int d;
06178 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06179 return d;
06180 }
06181
06182 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06183 {
06184 #ifdef IMAP_STORAGE
06185
06186
06187 char sequence[10];
06188 char mailbox[256];
06189 int res;
06190
06191
06192 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06193
06194 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06195 ast_mutex_lock(&vms->lock);
06196
06197 if (box == OLD_FOLDER) {
06198 mail_setflag(vms->mailstream, sequence, "\\Seen");
06199 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06200 } else if (box == NEW_FOLDER) {
06201 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06202 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06203 }
06204 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06205 ast_mutex_unlock(&vms->lock);
06206 return 0;
06207 }
06208
06209 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06210 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06211 if (mail_create(vms->mailstream, mailbox) == NIL)
06212 ast_debug(5, "Folder exists.\n");
06213 else
06214 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06215 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06216 ast_mutex_unlock(&vms->lock);
06217 return res;
06218 #else
06219 char *dir = vms->curdir;
06220 char *username = vms->username;
06221 char *context = vmu->context;
06222 char sfn[PATH_MAX];
06223 char dfn[PATH_MAX];
06224 char ddir[PATH_MAX];
06225 const char *dbox = mbox(vmu, box);
06226 int x, i;
06227 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06228
06229 if (vm_lock_path(ddir))
06230 return ERROR_LOCK_PATH;
06231
06232 x = last_message_index(vmu, ddir) + 1;
06233
06234 if (box == 10 && x >= vmu->maxdeletedmsg) {
06235 x--;
06236 for (i = 1; i <= x; i++) {
06237
06238 make_file(sfn, sizeof(sfn), ddir, i);
06239 make_file(dfn, sizeof(dfn), ddir, i - 1);
06240 if (EXISTS(ddir, i, sfn, NULL)) {
06241 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06242 } else
06243 break;
06244 }
06245 } else {
06246 if (x >= vmu->maxmsg) {
06247 ast_unlock_path(ddir);
06248 return -1;
06249 }
06250 }
06251 make_file(sfn, sizeof(sfn), dir, msg);
06252 make_file(dfn, sizeof(dfn), ddir, x);
06253 if (strcmp(sfn, dfn)) {
06254 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06255 }
06256 ast_unlock_path(ddir);
06257 #endif
06258 return 0;
06259 }
06260
06261 static int adsi_logo(unsigned char *buf)
06262 {
06263 int bytes = 0;
06264 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06265 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06266 return bytes;
06267 }
06268
06269 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06270 {
06271 unsigned char buf[256];
06272 int bytes = 0;
06273 int x;
06274 char num[5];
06275
06276 *useadsi = 0;
06277 bytes += ast_adsi_data_mode(buf + bytes);
06278 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06279
06280 bytes = 0;
06281 bytes += adsi_logo(buf);
06282 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06283 #ifdef DISPLAY
06284 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06285 #endif
06286 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06287 bytes += ast_adsi_data_mode(buf + bytes);
06288 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06289
06290 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06291 bytes = 0;
06292 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06293 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06294 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06295 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06296 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06297 return 0;
06298 }
06299
06300 #ifdef DISPLAY
06301
06302 bytes = 0;
06303 bytes += ast_adsi_logo(buf);
06304 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06305 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06306 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06307 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06308 #endif
06309 bytes = 0;
06310 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06311 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06312 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06313 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06314 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06315 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06316 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06317
06318 #ifdef DISPLAY
06319
06320 bytes = 0;
06321 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06322 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06323
06324 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06325 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06326 #endif
06327
06328 bytes = 0;
06329
06330 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06331 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06332 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06333 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06334 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06335 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06336 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06337
06338 #ifdef DISPLAY
06339
06340 bytes = 0;
06341 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06342 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06343 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06344 #endif
06345
06346 bytes = 0;
06347 for (x = 0; x < 5; x++) {
06348 snprintf(num, sizeof(num), "%d", x);
06349 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06350 }
06351 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06352 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06353
06354 #ifdef DISPLAY
06355
06356 bytes = 0;
06357 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06358 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06359 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06360 #endif
06361
06362 if (ast_adsi_end_download(chan)) {
06363 bytes = 0;
06364 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06365 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06366 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06367 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06368 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06369 return 0;
06370 }
06371 bytes = 0;
06372 bytes += ast_adsi_download_disconnect(buf + bytes);
06373 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06374 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06375
06376 ast_debug(1, "Done downloading scripts...\n");
06377
06378 #ifdef DISPLAY
06379
06380 bytes = 0;
06381 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06382 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06383 #endif
06384 ast_debug(1, "Restarting session...\n");
06385
06386 bytes = 0;
06387
06388 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06389 *useadsi = 1;
06390 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06391 } else
06392 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06393
06394 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06395 return 0;
06396 }
06397
06398 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06399 {
06400 int x;
06401 if (!ast_adsi_available(chan))
06402 return;
06403 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06404 if (x < 0)
06405 return;
06406 if (!x) {
06407 if (adsi_load_vmail(chan, useadsi)) {
06408 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06409 return;
06410 }
06411 } else
06412 *useadsi = 1;
06413 }
06414
06415 static void adsi_login(struct ast_channel *chan)
06416 {
06417 unsigned char buf[256];
06418 int bytes = 0;
06419 unsigned char keys[8];
06420 int x;
06421 if (!ast_adsi_available(chan))
06422 return;
06423
06424 for (x = 0; x < 8; x++)
06425 keys[x] = 0;
06426
06427 keys[3] = ADSI_KEY_APPS + 3;
06428
06429 bytes += adsi_logo(buf + bytes);
06430 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06431 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06432 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06433 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06434 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06435 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06436 bytes += ast_adsi_set_keys(buf + bytes, keys);
06437 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06438 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06439 }
06440
06441 static void adsi_password(struct ast_channel *chan)
06442 {
06443 unsigned char buf[256];
06444 int bytes = 0;
06445 unsigned char keys[8];
06446 int x;
06447 if (!ast_adsi_available(chan))
06448 return;
06449
06450 for (x = 0; x < 8; x++)
06451 keys[x] = 0;
06452
06453 keys[3] = ADSI_KEY_APPS + 3;
06454
06455 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06456 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06457 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06458 bytes += ast_adsi_set_keys(buf + bytes, keys);
06459 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06460 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06461 }
06462
06463 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06464 {
06465 unsigned char buf[256];
06466 int bytes = 0;
06467 unsigned char keys[8];
06468 int x, y;
06469
06470 if (!ast_adsi_available(chan))
06471 return;
06472
06473 for (x = 0; x < 5; x++) {
06474 y = ADSI_KEY_APPS + 12 + start + x;
06475 if (y > ADSI_KEY_APPS + 12 + 4)
06476 y = 0;
06477 keys[x] = ADSI_KEY_SKT | y;
06478 }
06479 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06480 keys[6] = 0;
06481 keys[7] = 0;
06482
06483 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06484 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06485 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06486 bytes += ast_adsi_set_keys(buf + bytes, keys);
06487 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06488
06489 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06490 }
06491
06492 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06493 {
06494 int bytes = 0;
06495 unsigned char buf[256];
06496 char buf1[256], buf2[256];
06497 char fn2[PATH_MAX];
06498
06499 char cid[256] = "";
06500 char *val;
06501 char *name, *num;
06502 char datetime[21] = "";
06503 FILE *f;
06504
06505 unsigned char keys[8];
06506
06507 int x;
06508
06509 if (!ast_adsi_available(chan))
06510 return;
06511
06512
06513 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06514 f = fopen(fn2, "r");
06515 if (f) {
06516 while (!feof(f)) {
06517 if (!fgets((char *) buf, sizeof(buf), f)) {
06518 continue;
06519 }
06520 if (!feof(f)) {
06521 char *stringp = NULL;
06522 stringp = (char *) buf;
06523 strsep(&stringp, "=");
06524 val = strsep(&stringp, "=");
06525 if (!ast_strlen_zero(val)) {
06526 if (!strcmp((char *) buf, "callerid"))
06527 ast_copy_string(cid, val, sizeof(cid));
06528 if (!strcmp((char *) buf, "origdate"))
06529 ast_copy_string(datetime, val, sizeof(datetime));
06530 }
06531 }
06532 }
06533 fclose(f);
06534 }
06535
06536 for (x = 0; x < 5; x++)
06537 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06538 keys[6] = 0x0;
06539 keys[7] = 0x0;
06540
06541 if (!vms->curmsg) {
06542
06543 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06544 }
06545 if (vms->curmsg >= vms->lastmsg) {
06546
06547 if (vms->curmsg) {
06548
06549 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06550 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06551
06552 } else {
06553
06554 keys[3] = 1;
06555 }
06556 }
06557
06558 if (!ast_strlen_zero(cid)) {
06559 ast_callerid_parse(cid, &name, &num);
06560 if (!name)
06561 name = num;
06562 } else
06563 name = "Unknown Caller";
06564
06565
06566
06567 if (vms->deleted[vms->curmsg])
06568 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06569
06570
06571 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06572 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06573 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06574 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06575
06576 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06577 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06578 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06579 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06580 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06581 bytes += ast_adsi_set_keys(buf + bytes, keys);
06582 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06583
06584 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06585 }
06586
06587 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06588 {
06589 int bytes = 0;
06590 unsigned char buf[256];
06591 unsigned char keys[8];
06592
06593 int x;
06594
06595 if (!ast_adsi_available(chan))
06596 return;
06597
06598
06599 for (x = 0; x < 5; x++)
06600 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06601
06602 keys[6] = 0x0;
06603 keys[7] = 0x0;
06604
06605 if (!vms->curmsg) {
06606
06607 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06608 }
06609 if (vms->curmsg >= vms->lastmsg) {
06610
06611 if (vms->curmsg) {
06612
06613 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06614 } else {
06615
06616 keys[3] = 1;
06617 }
06618 }
06619
06620
06621 if (vms->deleted[vms->curmsg])
06622 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06623
06624
06625 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06626 bytes += ast_adsi_set_keys(buf + bytes, keys);
06627 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06628
06629 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06630 }
06631
06632 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06633 {
06634 unsigned char buf[256] = "";
06635 char buf1[256] = "", buf2[256] = "";
06636 int bytes = 0;
06637 unsigned char keys[8];
06638 int x;
06639
06640 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06641 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06642 if (!ast_adsi_available(chan))
06643 return;
06644 if (vms->newmessages) {
06645 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06646 if (vms->oldmessages) {
06647 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06648 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06649 } else {
06650 snprintf(buf2, sizeof(buf2), "%s.", newm);
06651 }
06652 } else if (vms->oldmessages) {
06653 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06654 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06655 } else {
06656 strcpy(buf1, "You have no messages.");
06657 buf2[0] = ' ';
06658 buf2[1] = '\0';
06659 }
06660 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06661 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06662 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06663
06664 for (x = 0; x < 6; x++)
06665 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06666 keys[6] = 0;
06667 keys[7] = 0;
06668
06669
06670 if (vms->lastmsg < 0)
06671 keys[0] = 1;
06672 bytes += ast_adsi_set_keys(buf + bytes, keys);
06673
06674 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06675
06676 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06677 }
06678
06679 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06680 {
06681 unsigned char buf[256] = "";
06682 char buf1[256] = "", buf2[256] = "";
06683 int bytes = 0;
06684 unsigned char keys[8];
06685 int x;
06686
06687 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06688
06689 if (!ast_adsi_available(chan))
06690 return;
06691
06692
06693 for (x = 0; x < 6; x++)
06694 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06695
06696 keys[6] = 0;
06697 keys[7] = 0;
06698
06699 if ((vms->lastmsg + 1) < 1)
06700 keys[0] = 0;
06701
06702 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06703 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06704
06705 if (vms->lastmsg + 1)
06706 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06707 else
06708 strcpy(buf2, "no messages.");
06709 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06710 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06711 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06712 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06713 bytes += ast_adsi_set_keys(buf + bytes, keys);
06714
06715 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06716
06717 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06718
06719 }
06720
06721
06722
06723
06724
06725
06726
06727
06728
06729
06730
06731
06732
06733
06734
06735 static void adsi_goodbye(struct ast_channel *chan)
06736 {
06737 unsigned char buf[256];
06738 int bytes = 0;
06739
06740 if (!ast_adsi_available(chan))
06741 return;
06742 bytes += adsi_logo(buf + bytes);
06743 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06744 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06745 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06746 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06747
06748 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06749 }
06750
06751
06752
06753
06754
06755 static int get_folder(struct ast_channel *chan, int start)
06756 {
06757 int x;
06758 int d;
06759 char fn[PATH_MAX];
06760 d = ast_play_and_wait(chan, "vm-press");
06761 if (d)
06762 return d;
06763 for (x = start; x < 5; x++) {
06764 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06765 return d;
06766 d = ast_play_and_wait(chan, "vm-for");
06767 if (d)
06768 return d;
06769 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06770
06771
06772
06773
06774 if (x == 0) {
06775 if (ast_fileexists(fn, NULL, NULL)) {
06776 d = vm_play_folder_name(chan, fn);
06777 } else {
06778 ast_verb(1, "failed to find %s\n", fn);
06779 d = vm_play_folder_name(chan, "vm-INBOX");
06780 }
06781 } else {
06782 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06783 d = vm_play_folder_name(chan, fn);
06784 }
06785
06786 if (d)
06787 return d;
06788 d = ast_waitfordigit(chan, 500);
06789 if (d)
06790 return d;
06791 }
06792
06793 d = ast_play_and_wait(chan, "vm-tocancel");
06794 if (d)
06795 return d;
06796 d = ast_waitfordigit(chan, 4000);
06797 return d;
06798 }
06799
06800
06801
06802
06803
06804
06805
06806
06807
06808
06809
06810
06811
06812 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06813 {
06814 int res = 0;
06815 int loops = 0;
06816
06817 res = ast_play_and_wait(chan, fn);
06818 while (((res < '0') || (res > '9')) &&
06819 (res != '#') && (res >= 0) &&
06820 loops < 4) {
06821 res = get_folder(chan, 0);
06822 loops++;
06823 }
06824 if (loops == 4) {
06825 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06826 return '#';
06827 }
06828 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06829 return res;
06830 }
06831
06832
06833
06834
06835
06836
06837
06838
06839
06840
06841
06842
06843
06844
06845
06846
06847
06848
06849
06850 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06851 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06852 {
06853 int cmd = 0;
06854 int retries = 0, prepend_duration = 0, already_recorded = 0;
06855 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06856 char textfile[PATH_MAX];
06857 struct ast_config *msg_cfg;
06858 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06859 #ifndef IMAP_STORAGE
06860 signed char zero_gain = 0;
06861 #endif
06862 const char *duration_str;
06863
06864
06865 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06866 strcpy(textfile, msgfile);
06867 strcpy(backup, msgfile);
06868 strcpy(backup_textfile, msgfile);
06869 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06870 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06871 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06872
06873 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06874 *duration = atoi(duration_str);
06875 } else {
06876 *duration = 0;
06877 }
06878
06879 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06880 if (cmd)
06881 retries = 0;
06882 switch (cmd) {
06883 case '1':
06884
06885 #ifdef IMAP_STORAGE
06886
06887 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06888 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06889 ast_play_and_wait(chan, INTRO);
06890 ast_play_and_wait(chan, "beep");
06891 play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06892 cmd = 't';
06893 #else
06894
06895
06896
06897 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06898 strcpy(textfile, msgfile);
06899 strncat(textfile, ".txt", sizeof(textfile) - 1);
06900 *duration = 0;
06901
06902
06903 if (!msg_cfg) {
06904 cmd = 0;
06905 break;
06906 }
06907
06908
06909 #ifndef IMAP_STORAGE
06910 if (already_recorded) {
06911 ast_filecopy(backup, msgfile, NULL);
06912 copy(backup_textfile, textfile);
06913 }
06914 else {
06915 ast_filecopy(msgfile, backup, NULL);
06916 copy(textfile, backup_textfile);
06917 }
06918 #endif
06919 already_recorded = 1;
06920
06921 if (record_gain)
06922 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06923
06924 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06925
06926 if (cmd == 'S') {
06927 ast_stream_and_wait(chan, vm_pls_try_again, "");
06928 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06929 ast_filerename(backup, msgfile, NULL);
06930 }
06931
06932 if (record_gain)
06933 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06934
06935
06936 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06937 *duration = atoi(duration_str);
06938
06939 if (prepend_duration) {
06940 struct ast_category *msg_cat;
06941
06942 char duration_buf[12];
06943
06944 *duration += prepend_duration;
06945 msg_cat = ast_category_get(msg_cfg, "message");
06946 snprintf(duration_buf, 11, "%ld", *duration);
06947 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06948 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06949 }
06950 }
06951
06952 #endif
06953 break;
06954 case '2':
06955
06956 #ifdef IMAP_STORAGE
06957 *vms->introfn = '\0';
06958 #endif
06959 cmd = 't';
06960 break;
06961 case '*':
06962 cmd = '*';
06963 break;
06964 default:
06965
06966 already_recorded = 0;
06967
06968 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06969
06970 if (!cmd) {
06971 cmd = ast_play_and_wait(chan, "vm-starmain");
06972
06973 }
06974 if (!cmd) {
06975 cmd = ast_waitfordigit(chan, 6000);
06976 }
06977 if (!cmd) {
06978 retries++;
06979 }
06980 if (retries > 3) {
06981 cmd = '*';
06982 }
06983 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
06984 }
06985 }
06986
06987 if (msg_cfg)
06988 ast_config_destroy(msg_cfg);
06989 if (prepend_duration)
06990 *duration = prepend_duration;
06991
06992 if (already_recorded && cmd == -1) {
06993
06994 ast_filerename(backup, msgfile, NULL);
06995 rename(backup_textfile, textfile);
06996 }
06997
06998 if (cmd == 't' || cmd == 'S')
06999 cmd = 0;
07000 return cmd;
07001 }
07002
07003 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07004 {
07005 struct ast_event *event;
07006 char *mailbox, *context;
07007
07008
07009 context = mailbox = ast_strdupa(box);
07010 strsep(&context, "@");
07011 if (ast_strlen_zero(context))
07012 context = "default";
07013
07014 if (!(event = ast_event_new(AST_EVENT_MWI,
07015 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07016 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07017 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07018 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07019 AST_EVENT_IE_END))) {
07020 return;
07021 }
07022
07023 ast_event_queue_and_cache(event);
07024 }
07025
07026
07027
07028
07029
07030
07031
07032
07033
07034
07035
07036
07037
07038
07039
07040 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)
07041 {
07042 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07043 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07044 const char *category;
07045 char *myserveremail = serveremail;
07046
07047 ast_channel_lock(chan);
07048 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07049 category = ast_strdupa(category);
07050 }
07051 ast_channel_unlock(chan);
07052
07053 #ifndef IMAP_STORAGE
07054 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07055 #else
07056 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07057 #endif
07058 make_file(fn, sizeof(fn), todir, msgnum);
07059 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07060
07061 if (!ast_strlen_zero(vmu->attachfmt)) {
07062 if (strstr(fmt, vmu->attachfmt))
07063 fmt = vmu->attachfmt;
07064 else
07065 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);
07066 }
07067
07068
07069 fmt = ast_strdupa(fmt);
07070 stringp = fmt;
07071 strsep(&stringp, "|");
07072
07073 if (!ast_strlen_zero(vmu->serveremail))
07074 myserveremail = vmu->serveremail;
07075
07076 if (!ast_strlen_zero(vmu->email)) {
07077 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07078
07079 if (attach_user_voicemail)
07080 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07081
07082
07083 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07084
07085 if (attach_user_voicemail)
07086 DISPOSE(todir, msgnum);
07087 }
07088
07089 if (!ast_strlen_zero(vmu->pager)) {
07090 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07091 }
07092
07093 if (ast_test_flag(vmu, VM_DELETE))
07094 DELETE(todir, msgnum, fn, vmu);
07095
07096
07097 if (ast_app_has_voicemail(ext_context, NULL))
07098 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07099
07100 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07101
07102 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);
07103 run_externnotify(vmu->context, vmu->mailbox, flag);
07104
07105 #ifdef IMAP_STORAGE
07106 vm_delete(fn);
07107 if (ast_test_flag(vmu, VM_DELETE)) {
07108 vm_imap_delete(NULL, vms->curmsg, vmu);
07109 vms->newmessages--;
07110 }
07111 #endif
07112
07113 return 0;
07114 }
07115
07116
07117
07118
07119
07120
07121
07122
07123
07124
07125
07126
07127
07128
07129
07130
07131
07132
07133
07134
07135
07136
07137
07138
07139
07140
07141
07142
07143 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)
07144 {
07145 #ifdef IMAP_STORAGE
07146 int todircount = 0;
07147 struct vm_state *dstvms;
07148 #endif
07149 char username[70]="";
07150 char fn[PATH_MAX];
07151 char ecodes[16] = "#";
07152 int res = 0, cmd = 0;
07153 struct ast_vm_user *receiver = NULL, *vmtmp;
07154 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07155 char *stringp;
07156 const char *s;
07157 int saved_messages = 0;
07158 int valid_extensions = 0;
07159 char *dir;
07160 int curmsg;
07161 char urgent_str[7] = "";
07162 int prompt_played = 0;
07163 #ifndef IMAP_STORAGE
07164 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07165 #endif
07166 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07167 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07168 }
07169
07170 if (vms == NULL) return -1;
07171 dir = vms->curdir;
07172 curmsg = vms->curmsg;
07173
07174 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07175 while (!res && !valid_extensions) {
07176 int use_directory = 0;
07177 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07178 int done = 0;
07179 int retries = 0;
07180 cmd = 0;
07181 while ((cmd >= 0) && !done ){
07182 if (cmd)
07183 retries = 0;
07184 switch (cmd) {
07185 case '1':
07186 use_directory = 0;
07187 done = 1;
07188 break;
07189 case '2':
07190 use_directory = 1;
07191 done = 1;
07192 break;
07193 case '*':
07194 cmd = 't';
07195 done = 1;
07196 break;
07197 default:
07198
07199 cmd = ast_play_and_wait(chan, "vm-forward");
07200 if (!cmd) {
07201 cmd = ast_waitfordigit(chan, 3000);
07202 }
07203 if (!cmd) {
07204 retries++;
07205 }
07206 if (retries > 3) {
07207 cmd = 't';
07208 done = 1;
07209 }
07210 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07211 }
07212 }
07213 if (cmd < 0 || cmd == 't')
07214 break;
07215 }
07216
07217 if (use_directory) {
07218
07219
07220 char old_context[sizeof(chan->context)];
07221 char old_exten[sizeof(chan->exten)];
07222 int old_priority;
07223 struct ast_app* directory_app;
07224
07225 directory_app = pbx_findapp("Directory");
07226 if (directory_app) {
07227 char vmcontext[256];
07228
07229 memcpy(old_context, chan->context, sizeof(chan->context));
07230 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07231 old_priority = chan->priority;
07232
07233
07234 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07235 res = pbx_exec(chan, directory_app, vmcontext);
07236
07237 ast_copy_string(username, chan->exten, sizeof(username));
07238
07239
07240 memcpy(chan->context, old_context, sizeof(chan->context));
07241 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07242 chan->priority = old_priority;
07243 } else {
07244 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07245 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07246 }
07247 } else {
07248
07249 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07250 res = ast_streamfile(chan, "vm-extension", chan->language);
07251 prompt_played++;
07252 if (res || prompt_played > 4)
07253 break;
07254 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07255 break;
07256 }
07257
07258
07259 if (ast_strlen_zero(username))
07260 continue;
07261 stringp = username;
07262 s = strsep(&stringp, "*");
07263
07264 valid_extensions = 1;
07265 while (s) {
07266 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07267 int oldmsgs;
07268 int newmsgs;
07269 int capacity;
07270 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07271 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07272
07273 res = ast_play_and_wait(chan, "pbx-invalid");
07274 valid_extensions = 0;
07275 break;
07276 }
07277 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07278 if ((newmsgs + oldmsgs) >= capacity) {
07279 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07280 res = ast_play_and_wait(chan, "vm-mailboxfull");
07281 valid_extensions = 0;
07282 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07283 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07284 free_user(vmtmp);
07285 }
07286 inprocess_count(receiver->mailbox, receiver->context, -1);
07287 break;
07288 }
07289 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07290 } else {
07291
07292
07293
07294
07295
07296 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07297 free_user(receiver);
07298 }
07299 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07300
07301 res = ast_play_and_wait(chan, "pbx-invalid");
07302 valid_extensions = 0;
07303 break;
07304 }
07305
07306
07307 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07308 RETRIEVE(fn, -1, s, receiver->context);
07309 if (ast_fileexists(fn, NULL, NULL) > 0) {
07310 res = ast_stream_and_wait(chan, fn, ecodes);
07311 if (res) {
07312 DISPOSE(fn, -1);
07313 return res;
07314 }
07315 } else {
07316 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07317 }
07318 DISPOSE(fn, -1);
07319
07320 s = strsep(&stringp, "*");
07321 }
07322
07323 if (valid_extensions)
07324 break;
07325 }
07326
07327 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07328 return res;
07329 if (is_new_message == 1) {
07330 struct leave_vm_options leave_options;
07331 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07332 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07333
07334
07335 memset(&leave_options, 0, sizeof(leave_options));
07336 leave_options.record_gain = record_gain;
07337 cmd = leave_voicemail(chan, mailbox, &leave_options);
07338 } else {
07339
07340 long duration = 0;
07341 struct vm_state vmstmp;
07342 int copy_msg_result = 0;
07343 memcpy(&vmstmp, vms, sizeof(vmstmp));
07344
07345 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07346
07347 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07348 if (!cmd) {
07349 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07350 #ifdef IMAP_STORAGE
07351 int attach_user_voicemail;
07352 char *myserveremail = serveremail;
07353
07354
07355 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07356 if (!dstvms) {
07357 dstvms = create_vm_state_from_user(vmtmp);
07358 }
07359 if (dstvms) {
07360 init_mailstream(dstvms, 0);
07361 if (!dstvms->mailstream) {
07362 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07363 } else {
07364 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07365 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07366 }
07367 } else {
07368 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07369 }
07370 if (!ast_strlen_zero(vmtmp->serveremail))
07371 myserveremail = vmtmp->serveremail;
07372 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07373
07374 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07375 dstvms->curbox,
07376 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07377 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07378 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07379 NULL, urgent_str);
07380 #else
07381 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07382 #endif
07383 saved_messages++;
07384 AST_LIST_REMOVE_CURRENT(list);
07385 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07386 free_user(vmtmp);
07387 if (res)
07388 break;
07389 }
07390 AST_LIST_TRAVERSE_SAFE_END;
07391 if (saved_messages > 0 && !copy_msg_result) {
07392
07393
07394
07395
07396
07397
07398
07399
07400 #ifdef IMAP_STORAGE
07401
07402 if (ast_strlen_zero(vmstmp.introfn))
07403 #endif
07404 res = ast_play_and_wait(chan, "vm-msgsaved");
07405 }
07406 #ifndef IMAP_STORAGE
07407 else {
07408
07409 res = ast_play_and_wait(chan, "vm-mailboxfull");
07410 }
07411
07412 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07413 strcpy(textfile, msgfile);
07414 strcpy(backup, msgfile);
07415 strcpy(backup_textfile, msgfile);
07416 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07417 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07418 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07419 if (ast_fileexists(backup, NULL, NULL) > 0) {
07420 ast_filerename(backup, msgfile, NULL);
07421 rename(backup_textfile, textfile);
07422 }
07423 #endif
07424 }
07425 DISPOSE(dir, curmsg);
07426 #ifndef IMAP_STORAGE
07427 if (cmd) {
07428 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07429 strcpy(textfile, msgfile);
07430 strcpy(backup_textfile, msgfile);
07431 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07432 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07433 rename(backup_textfile, textfile);
07434 }
07435 #endif
07436 }
07437
07438
07439 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07440 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07441 free_user(vmtmp);
07442 }
07443 return res ? res : cmd;
07444 }
07445
07446 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07447 {
07448 int res;
07449 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07450 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07451 return res;
07452 }
07453
07454 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07455 {
07456 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07457 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);
07458 }
07459
07460 static int play_message_category(struct ast_channel *chan, const char *category)
07461 {
07462 int res = 0;
07463
07464 if (!ast_strlen_zero(category))
07465 res = ast_play_and_wait(chan, category);
07466
07467 if (res) {
07468 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07469 res = 0;
07470 }
07471
07472 return res;
07473 }
07474
07475 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07476 {
07477 int res = 0;
07478 struct vm_zone *the_zone = NULL;
07479 time_t t;
07480
07481 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07482 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07483 return 0;
07484 }
07485
07486
07487 if (!ast_strlen_zero(vmu->zonetag)) {
07488
07489 struct vm_zone *z;
07490 AST_LIST_LOCK(&zones);
07491 AST_LIST_TRAVERSE(&zones, z, list) {
07492 if (!strcmp(z->name, vmu->zonetag)) {
07493 the_zone = z;
07494 break;
07495 }
07496 }
07497 AST_LIST_UNLOCK(&zones);
07498 }
07499
07500
07501 #if 0
07502
07503 ast_localtime(&t, &time_now, NULL);
07504 tv_now = ast_tvnow();
07505 ast_localtime(&tv_now, &time_then, NULL);
07506
07507
07508 if (time_now.tm_year == time_then.tm_year)
07509 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07510 else
07511 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07512 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07513
07514
07515 #endif
07516 if (the_zone) {
07517 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07518 } else if (!strncasecmp(chan->language, "de", 2)) {
07519 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07520 } else if (!strncasecmp(chan->language, "gr", 2)) {
07521 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07522 } else if (!strncasecmp(chan->language, "it", 2)) {
07523 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);
07524 } else if (!strncasecmp(chan->language, "nl", 2)) {
07525 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07526 } else if (!strncasecmp(chan->language, "no", 2)) {
07527 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07528 } else if (!strncasecmp(chan->language, "pl", 2)) {
07529 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07530 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07531 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);
07532 } else if (!strncasecmp(chan->language, "se", 2)) {
07533 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07534 } else if (!strncasecmp(chan->language, "zh", 2)) {
07535 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07536 } else if (!strncasecmp(chan->language, "vi", 2)) {
07537 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);
07538 } else {
07539 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07540 }
07541 #if 0
07542 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07543 #endif
07544 return res;
07545 }
07546
07547
07548
07549 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07550 {
07551 int res = 0;
07552 int i;
07553 char *callerid, *name;
07554 char prefile[PATH_MAX] = "";
07555
07556
07557
07558
07559
07560
07561
07562
07563
07564 if ((cid == NULL)||(context == NULL))
07565 return res;
07566
07567
07568 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07569 ast_callerid_parse(cid, &name, &callerid);
07570 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07571
07572
07573 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07574 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07575 if ((strcmp(cidinternalcontexts[i], context) == 0))
07576 break;
07577 }
07578 if (i != MAX_NUM_CID_CONTEXTS){
07579 if (!res) {
07580 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07581 if (!ast_strlen_zero(prefile)) {
07582
07583 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07584 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07585 if (!callback)
07586 res = wait_file2(chan, vms, "vm-from");
07587 res = ast_stream_and_wait(chan, prefile, "");
07588 } else {
07589 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07590
07591 if (!callback)
07592 res = wait_file2(chan, vms, "vm-from-extension");
07593 res = ast_say_digit_str(chan, callerid, "", chan->language);
07594 }
07595 }
07596 }
07597 } else if (!res) {
07598 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07599
07600 if (!callback)
07601 res = wait_file2(chan, vms, "vm-from-phonenumber");
07602 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07603 }
07604 } else {
07605
07606 ast_debug(1, "VM-CID: From an unknown number\n");
07607
07608 res = wait_file2(chan, vms, "vm-unknown-caller");
07609 }
07610 return res;
07611 }
07612
07613 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07614 {
07615 int res = 0;
07616 int durationm;
07617 int durations;
07618
07619 if (duration == NULL)
07620 return res;
07621
07622
07623 durations = atoi(duration);
07624 durationm = (durations / 60);
07625
07626 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07627
07628 if ((!res) && (durationm >= minduration)) {
07629 res = wait_file2(chan, vms, "vm-duration");
07630
07631
07632 if (!strncasecmp(chan->language, "pl", 2)) {
07633 div_t num = div(durationm, 10);
07634
07635 if (durationm == 1) {
07636 res = ast_play_and_wait(chan, "digits/1z");
07637 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07638 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07639 if (num.rem == 2) {
07640 if (!num.quot) {
07641 res = ast_play_and_wait(chan, "digits/2-ie");
07642 } else {
07643 res = say_and_wait(chan, durationm - 2 , chan->language);
07644 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07645 }
07646 } else {
07647 res = say_and_wait(chan, durationm, chan->language);
07648 }
07649 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07650 } else {
07651 res = say_and_wait(chan, durationm, chan->language);
07652 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07653 }
07654
07655 } else {
07656 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07657 res = wait_file2(chan, vms, "vm-minutes");
07658 }
07659 }
07660 return res;
07661 }
07662
07663 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07664 {
07665 int res = 0;
07666 char filename[256], *cid;
07667 const char *origtime, *context, *category, *duration, *flag;
07668 struct ast_config *msg_cfg;
07669 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07670
07671 vms->starting = 0;
07672 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07673 adsi_message(chan, vms);
07674 if (!vms->curmsg) {
07675 res = wait_file2(chan, vms, "vm-first");
07676 } else if (vms->curmsg == vms->lastmsg) {
07677 res = wait_file2(chan, vms, "vm-last");
07678 }
07679
07680 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07681 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07682 msg_cfg = ast_config_load(filename, config_flags);
07683 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07684 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07685 return 0;
07686 }
07687 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07688
07689
07690 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07691 res = wait_file2(chan, vms, "vm-Urgent");
07692 }
07693
07694 if (!res) {
07695
07696
07697 if (!strncasecmp(chan->language, "pl", 2)) {
07698 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07699 int ten, one;
07700 char nextmsg[256];
07701 ten = (vms->curmsg + 1) / 10;
07702 one = (vms->curmsg + 1) % 10;
07703
07704 if (vms->curmsg < 20) {
07705 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07706 res = wait_file2(chan, vms, nextmsg);
07707 } else {
07708 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07709 res = wait_file2(chan, vms, nextmsg);
07710 if (one > 0) {
07711 if (!res) {
07712 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07713 res = wait_file2(chan, vms, nextmsg);
07714 }
07715 }
07716 }
07717 }
07718 if (!res)
07719 res = wait_file2(chan, vms, "vm-message");
07720
07721 } else if (!strncasecmp(chan->language, "he", 2)) {
07722 if (!vms->curmsg) {
07723 res = wait_file2(chan, vms, "vm-message");
07724 res = wait_file2(chan, vms, "vm-first");
07725 } else if (vms->curmsg == vms->lastmsg) {
07726 res = wait_file2(chan, vms, "vm-message");
07727 res = wait_file2(chan, vms, "vm-last");
07728 } else {
07729 res = wait_file2(chan, vms, "vm-message");
07730 res = wait_file2(chan, vms, "vm-number");
07731 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07732 }
07733
07734 } else if (!strncasecmp(chan->language, "vi", 2)) {
07735 if (!vms->curmsg) {
07736 res = wait_file2(chan, vms, "vm-message");
07737 res = wait_file2(chan, vms, "vm-first");
07738 } else if (vms->curmsg == vms->lastmsg) {
07739 res = wait_file2(chan, vms, "vm-message");
07740 res = wait_file2(chan, vms, "vm-last");
07741 } else {
07742 res = wait_file2(chan, vms, "vm-message");
07743 res = wait_file2(chan, vms, "vm-number");
07744 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07745 }
07746 } else {
07747 if (!strncasecmp(chan->language, "se", 2)) {
07748 res = wait_file2(chan, vms, "vm-meddelandet");
07749 } else {
07750 res = wait_file2(chan, vms, "vm-message");
07751 }
07752 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07753 if (!res) {
07754 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07755 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07756 }
07757 }
07758 }
07759 }
07760
07761 if (!msg_cfg) {
07762 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07763 return 0;
07764 }
07765
07766 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07767 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07768 DISPOSE(vms->curdir, vms->curmsg);
07769 ast_config_destroy(msg_cfg);
07770 return 0;
07771 }
07772
07773 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07774 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07775 category = ast_variable_retrieve(msg_cfg, "message", "category");
07776
07777 context = ast_variable_retrieve(msg_cfg, "message", "context");
07778 if (!strncasecmp("macro", context, 5))
07779 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07780 if (!res) {
07781 res = play_message_category(chan, category);
07782 }
07783 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07784 res = play_message_datetime(chan, vmu, origtime, filename);
07785 }
07786 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07787 res = play_message_callerid(chan, vms, cid, context, 0);
07788 }
07789 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07790 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07791 }
07792
07793 if (res == '1') {
07794 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07795 res = 0;
07796 }
07797 ast_config_destroy(msg_cfg);
07798
07799 if (!res) {
07800 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07801 vms->heard[vms->curmsg] = 1;
07802 #ifdef IMAP_STORAGE
07803
07804
07805
07806 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07807 wait_file(chan, vms, vms->introfn);
07808 }
07809 #endif
07810 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07811 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07812 res = 0;
07813 }
07814 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07815 }
07816 DISPOSE(vms->curdir, vms->curmsg);
07817 return res;
07818 }
07819
07820 #ifdef IMAP_STORAGE
07821 static int imap_remove_file(char *dir, int msgnum)
07822 {
07823 char fn[PATH_MAX];
07824 char full_fn[PATH_MAX];
07825 char intro[PATH_MAX] = {0,};
07826
07827 if (msgnum > -1) {
07828 make_file(fn, sizeof(fn), dir, msgnum);
07829 snprintf(intro, sizeof(intro), "%sintro", fn);
07830 } else
07831 ast_copy_string(fn, dir, sizeof(fn));
07832
07833 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07834 ast_filedelete(fn, NULL);
07835 if (!ast_strlen_zero(intro)) {
07836 ast_filedelete(intro, NULL);
07837 }
07838 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07839 unlink(full_fn);
07840 }
07841 return 0;
07842 }
07843
07844
07845
07846 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07847 {
07848 char *file, *filename;
07849 char *attachment;
07850 char arg[10];
07851 int i;
07852 BODY* body;
07853
07854 file = strrchr(ast_strdupa(dir), '/');
07855 if (file) {
07856 *file++ = '\0';
07857 } else {
07858 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07859 return -1;
07860 }
07861
07862 ast_mutex_lock(&vms->lock);
07863 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07864 mail_fetchstructure(vms->mailstream, i + 1, &body);
07865
07866 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07867 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07868 } else {
07869 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07870 ast_mutex_unlock(&vms->lock);
07871 return -1;
07872 }
07873 filename = strsep(&attachment, ".");
07874 if (!strcmp(filename, file)) {
07875 sprintf(arg, "%d", i + 1);
07876 mail_setflag(vms->mailstream, arg, "\\DELETED");
07877 }
07878 }
07879 mail_expunge(vms->mailstream);
07880 ast_mutex_unlock(&vms->lock);
07881 return 0;
07882 }
07883
07884 #elif !defined(IMAP_STORAGE)
07885 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07886 {
07887 int count_msg, last_msg;
07888
07889 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07890
07891
07892
07893
07894 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07895
07896
07897 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07898
07899
07900 count_msg = count_messages(vmu, vms->curdir);
07901 if (count_msg < 0) {
07902 return count_msg;
07903 } else {
07904 vms->lastmsg = count_msg - 1;
07905 }
07906
07907 if (vm_allocate_dh(vms, vmu, count_msg)) {
07908 return -1;
07909 }
07910
07911
07912
07913
07914
07915
07916
07917
07918 if (vm_lock_path(vms->curdir)) {
07919 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07920 return ERROR_LOCK_PATH;
07921 }
07922
07923
07924 last_msg = last_message_index(vmu, vms->curdir);
07925 ast_unlock_path(vms->curdir);
07926
07927 if (last_msg < -1) {
07928 return last_msg;
07929 } else if (vms->lastmsg != last_msg) {
07930 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
07931 resequence_mailbox(vmu, vms->curdir, count_msg);
07932 }
07933
07934 return 0;
07935 }
07936 #endif
07937
07938 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07939 {
07940 int x = 0;
07941 int last_msg_idx = 0;
07942
07943 #ifndef IMAP_STORAGE
07944 int res = 0, nummsg;
07945 char fn2[PATH_MAX];
07946 #endif
07947
07948 if (vms->lastmsg <= -1) {
07949 goto done;
07950 }
07951
07952 vms->curmsg = -1;
07953 #ifndef IMAP_STORAGE
07954
07955 if (vm_lock_path(vms->curdir)) {
07956 return ERROR_LOCK_PATH;
07957 }
07958
07959
07960 last_msg_idx = last_message_index(vmu, vms->curdir);
07961 if (last_msg_idx != vms->lastmsg) {
07962 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
07963 }
07964
07965
07966 for (x = 0; x < last_msg_idx + 1; x++) {
07967 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07968
07969 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07970 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07971 break;
07972 }
07973 vms->curmsg++;
07974 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07975 if (strcmp(vms->fn, fn2)) {
07976 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07977 }
07978 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07979
07980 res = save_to_folder(vmu, vms, x, 1);
07981 if (res == ERROR_LOCK_PATH) {
07982
07983 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07984 vms->deleted[x] = 0;
07985 vms->heard[x] = 0;
07986 --x;
07987 }
07988 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07989
07990 res = save_to_folder(vmu, vms, x, 10);
07991 if (res == ERROR_LOCK_PATH) {
07992
07993 vms->deleted[x] = 0;
07994 vms->heard[x] = 0;
07995 --x;
07996 }
07997 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07998
07999
08000 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08001 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08002 DELETE(vms->curdir, x, vms->fn, vmu);
08003 }
08004 }
08005 }
08006
08007
08008 nummsg = x - 1;
08009 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08010 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08011 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08012 DELETE(vms->curdir, x, vms->fn, vmu);
08013 }
08014 }
08015 ast_unlock_path(vms->curdir);
08016 #else
08017 if (vms->deleted) {
08018
08019
08020 last_msg_idx = vms->dh_arraysize;
08021 for (x = last_msg_idx - 1; x >= 0; x--) {
08022 if (vms->deleted[x]) {
08023 ast_debug(3, "IMAP delete of %d\n", x);
08024 DELETE(vms->curdir, x, vms->fn, vmu);
08025 }
08026 }
08027 }
08028 #endif
08029
08030 done:
08031 if (vms->deleted && last_msg_idx) {
08032 ast_free(vms->deleted);
08033 }
08034 if (vms->heard && last_msg_idx) {
08035 ast_free(vms->heard);
08036 }
08037
08038 return 0;
08039 }
08040
08041
08042
08043
08044
08045
08046
08047 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08048 {
08049 int cmd;
08050 char *buf;
08051
08052 buf = alloca(strlen(box) + 2);
08053 strcpy(buf, box);
08054 strcat(buf, "s");
08055
08056 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08057 cmd = ast_play_and_wait(chan, buf);
08058 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08059 } else {
08060 cmd = ast_play_and_wait(chan, "vm-messages");
08061 return cmd ? cmd : ast_play_and_wait(chan, box);
08062 }
08063 }
08064
08065 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08066 {
08067 int cmd;
08068
08069 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08070 if (!strcasecmp(box, "vm-INBOX"))
08071 cmd = ast_play_and_wait(chan, "vm-new-e");
08072 else
08073 cmd = ast_play_and_wait(chan, "vm-old-e");
08074 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08075 } else {
08076 cmd = ast_play_and_wait(chan, "vm-messages");
08077 return cmd ? cmd : ast_play_and_wait(chan, box);
08078 }
08079 }
08080
08081 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08082 {
08083 int cmd;
08084
08085 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08086 cmd = ast_play_and_wait(chan, "vm-messages");
08087 return cmd ? cmd : ast_play_and_wait(chan, box);
08088 } else {
08089 cmd = ast_play_and_wait(chan, box);
08090 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08091 }
08092 }
08093
08094 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08095 {
08096 int cmd;
08097
08098 if ( !strncasecmp(chan->language, "it", 2) ||
08099 !strncasecmp(chan->language, "es", 2) ||
08100 !strncasecmp(chan->language, "pt", 2)) {
08101 cmd = ast_play_and_wait(chan, "vm-messages");
08102 return cmd ? cmd : ast_play_and_wait(chan, box);
08103 } else if (!strncasecmp(chan->language, "gr", 2)) {
08104 return vm_play_folder_name_gr(chan, box);
08105 } else if (!strncasecmp(chan->language, "he", 2)) {
08106 return ast_play_and_wait(chan, box);
08107 } else if (!strncasecmp(chan->language, "pl", 2)) {
08108 return vm_play_folder_name_pl(chan, box);
08109 } else if (!strncasecmp(chan->language, "ua", 2)) {
08110 return vm_play_folder_name_ua(chan, box);
08111 } else if (!strncasecmp(chan->language, "vi", 2)) {
08112 return ast_play_and_wait(chan, box);
08113 } else {
08114 cmd = ast_play_and_wait(chan, box);
08115 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08116 }
08117 }
08118
08119
08120
08121
08122
08123
08124
08125
08126
08127
08128
08129
08130
08131 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08132 {
08133 int res = 0;
08134
08135 if (vms->newmessages) {
08136 res = ast_play_and_wait(chan, "vm-youhave");
08137 if (!res)
08138 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08139 if (!res) {
08140 if ((vms->newmessages == 1)) {
08141 res = ast_play_and_wait(chan, "vm-INBOX");
08142 if (!res)
08143 res = ast_play_and_wait(chan, "vm-message");
08144 } else {
08145 res = ast_play_and_wait(chan, "vm-INBOXs");
08146 if (!res)
08147 res = ast_play_and_wait(chan, "vm-messages");
08148 }
08149 }
08150 } else if (vms->oldmessages){
08151 res = ast_play_and_wait(chan, "vm-youhave");
08152 if (!res)
08153 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08154 if ((vms->oldmessages == 1)){
08155 res = ast_play_and_wait(chan, "vm-Old");
08156 if (!res)
08157 res = ast_play_and_wait(chan, "vm-message");
08158 } else {
08159 res = ast_play_and_wait(chan, "vm-Olds");
08160 if (!res)
08161 res = ast_play_and_wait(chan, "vm-messages");
08162 }
08163 } else if (!vms->oldmessages && !vms->newmessages)
08164 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08165 return res;
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
08198
08199
08200
08201
08202
08203
08204
08205
08206
08207
08208
08209
08210
08211
08212
08213
08214
08215
08216
08217
08218
08219
08220
08221
08222
08223
08224
08225 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08226 {
08227 int res;
08228 int lastnum = 0;
08229
08230 res = ast_play_and_wait(chan, "vm-youhave");
08231
08232 if (!res && vms->newmessages) {
08233 lastnum = vms->newmessages;
08234
08235 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08236 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08237 }
08238
08239 if (!res && vms->oldmessages) {
08240 res = ast_play_and_wait(chan, "vm-and");
08241 }
08242 }
08243
08244 if (!res && vms->oldmessages) {
08245 lastnum = vms->oldmessages;
08246
08247 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08248 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08249 }
08250 }
08251
08252 if (!res) {
08253 if (lastnum == 0) {
08254 res = ast_play_and_wait(chan, "vm-no");
08255 }
08256 if (!res) {
08257 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08258 }
08259 }
08260
08261 return res;
08262 }
08263
08264
08265 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08266 {
08267 int res = 0;
08268
08269
08270 if (!res) {
08271 if ((vms->newmessages) || (vms->oldmessages)) {
08272 res = ast_play_and_wait(chan, "vm-youhave");
08273 }
08274
08275
08276
08277
08278
08279 if (vms->newmessages) {
08280 if (!res) {
08281 if (vms->newmessages == 1) {
08282 res = ast_play_and_wait(chan, "vm-INBOX1");
08283 } else {
08284 if (vms->newmessages == 2) {
08285 res = ast_play_and_wait(chan, "vm-shtei");
08286 } else {
08287 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08288 }
08289 res = ast_play_and_wait(chan, "vm-INBOX");
08290 }
08291 }
08292 if (vms->oldmessages && !res) {
08293 res = ast_play_and_wait(chan, "vm-and");
08294 if (vms->oldmessages == 1) {
08295 res = ast_play_and_wait(chan, "vm-Old1");
08296 } else {
08297 if (vms->oldmessages == 2) {
08298 res = ast_play_and_wait(chan, "vm-shtei");
08299 } else {
08300 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08301 }
08302 res = ast_play_and_wait(chan, "vm-Old");
08303 }
08304 }
08305 }
08306 if (!res && vms->oldmessages && !vms->newmessages) {
08307 if (!res) {
08308 if (vms->oldmessages == 1) {
08309 res = ast_play_and_wait(chan, "vm-Old1");
08310 } else {
08311 if (vms->oldmessages == 2) {
08312 res = ast_play_and_wait(chan, "vm-shtei");
08313 } else {
08314 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08315 }
08316 res = ast_play_and_wait(chan, "vm-Old");
08317 }
08318 }
08319 }
08320 if (!res) {
08321 if (!vms->oldmessages && !vms->newmessages) {
08322 if (!res) {
08323 res = ast_play_and_wait(chan, "vm-nomessages");
08324 }
08325 }
08326 }
08327 }
08328 return res;
08329 }
08330
08331
08332 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08333 {
08334 int res;
08335
08336
08337 res = ast_play_and_wait(chan, "vm-youhave");
08338 if (!res) {
08339 if (vms->urgentmessages) {
08340 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08341 if (!res)
08342 res = ast_play_and_wait(chan, "vm-Urgent");
08343 if ((vms->oldmessages || vms->newmessages) && !res) {
08344 res = ast_play_and_wait(chan, "vm-and");
08345 } else if (!res) {
08346 if ((vms->urgentmessages == 1))
08347 res = ast_play_and_wait(chan, "vm-message");
08348 else
08349 res = ast_play_and_wait(chan, "vm-messages");
08350 }
08351 }
08352 if (vms->newmessages) {
08353 res = say_and_wait(chan, vms->newmessages, chan->language);
08354 if (!res)
08355 res = ast_play_and_wait(chan, "vm-INBOX");
08356 if (vms->oldmessages && !res)
08357 res = ast_play_and_wait(chan, "vm-and");
08358 else if (!res) {
08359 if ((vms->newmessages == 1))
08360 res = ast_play_and_wait(chan, "vm-message");
08361 else
08362 res = ast_play_and_wait(chan, "vm-messages");
08363 }
08364
08365 }
08366 if (!res && vms->oldmessages) {
08367 res = say_and_wait(chan, vms->oldmessages, chan->language);
08368 if (!res)
08369 res = ast_play_and_wait(chan, "vm-Old");
08370 if (!res) {
08371 if (vms->oldmessages == 1)
08372 res = ast_play_and_wait(chan, "vm-message");
08373 else
08374 res = ast_play_and_wait(chan, "vm-messages");
08375 }
08376 }
08377 if (!res) {
08378 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08379 res = ast_play_and_wait(chan, "vm-no");
08380 if (!res)
08381 res = ast_play_and_wait(chan, "vm-messages");
08382 }
08383 }
08384 }
08385 return res;
08386 }
08387
08388
08389 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08390 {
08391
08392 int res;
08393 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08394 res = ast_play_and_wait(chan, "vm-no") ||
08395 ast_play_and_wait(chan, "vm-message");
08396 else
08397 res = ast_play_and_wait(chan, "vm-youhave");
08398 if (!res && vms->newmessages) {
08399 res = (vms->newmessages == 1) ?
08400 ast_play_and_wait(chan, "digits/un") ||
08401 ast_play_and_wait(chan, "vm-nuovo") ||
08402 ast_play_and_wait(chan, "vm-message") :
08403
08404 say_and_wait(chan, vms->newmessages, chan->language) ||
08405 ast_play_and_wait(chan, "vm-nuovi") ||
08406 ast_play_and_wait(chan, "vm-messages");
08407 if (!res && vms->oldmessages)
08408 res = ast_play_and_wait(chan, "vm-and");
08409 }
08410 if (!res && vms->oldmessages) {
08411 res = (vms->oldmessages == 1) ?
08412 ast_play_and_wait(chan, "digits/un") ||
08413 ast_play_and_wait(chan, "vm-vecchio") ||
08414 ast_play_and_wait(chan, "vm-message") :
08415
08416 say_and_wait(chan, vms->oldmessages, chan->language) ||
08417 ast_play_and_wait(chan, "vm-vecchi") ||
08418 ast_play_and_wait(chan, "vm-messages");
08419 }
08420 return res;
08421 }
08422
08423
08424 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08425 {
08426
08427 int res;
08428 div_t num;
08429
08430 if (!vms->oldmessages && !vms->newmessages) {
08431 res = ast_play_and_wait(chan, "vm-no");
08432 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08433 return res;
08434 } else {
08435 res = ast_play_and_wait(chan, "vm-youhave");
08436 }
08437
08438 if (vms->newmessages) {
08439 num = div(vms->newmessages, 10);
08440 if (vms->newmessages == 1) {
08441 res = ast_play_and_wait(chan, "digits/1-a");
08442 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08443 res = res ? res : ast_play_and_wait(chan, "vm-message");
08444 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08445 if (num.rem == 2) {
08446 if (!num.quot) {
08447 res = ast_play_and_wait(chan, "digits/2-ie");
08448 } else {
08449 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08450 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08451 }
08452 } else {
08453 res = say_and_wait(chan, vms->newmessages, chan->language);
08454 }
08455 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08456 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08457 } else {
08458 res = say_and_wait(chan, vms->newmessages, chan->language);
08459 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08460 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08461 }
08462 if (!res && vms->oldmessages)
08463 res = ast_play_and_wait(chan, "vm-and");
08464 }
08465 if (!res && vms->oldmessages) {
08466 num = div(vms->oldmessages, 10);
08467 if (vms->oldmessages == 1) {
08468 res = ast_play_and_wait(chan, "digits/1-a");
08469 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08470 res = res ? res : ast_play_and_wait(chan, "vm-message");
08471 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08472 if (num.rem == 2) {
08473 if (!num.quot) {
08474 res = ast_play_and_wait(chan, "digits/2-ie");
08475 } else {
08476 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08477 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08478 }
08479 } else {
08480 res = say_and_wait(chan, vms->oldmessages, chan->language);
08481 }
08482 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08483 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08484 } else {
08485 res = say_and_wait(chan, vms->oldmessages, chan->language);
08486 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08487 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08488 }
08489 }
08490
08491 return res;
08492 }
08493
08494
08495 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08496 {
08497
08498 int res;
08499
08500 res = ast_play_and_wait(chan, "vm-youhave");
08501 if (res)
08502 return res;
08503
08504 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08505 res = ast_play_and_wait(chan, "vm-no");
08506 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08507 return res;
08508 }
08509
08510 if (vms->newmessages) {
08511 if ((vms->newmessages == 1)) {
08512 res = ast_play_and_wait(chan, "digits/ett");
08513 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08514 res = res ? res : ast_play_and_wait(chan, "vm-message");
08515 } else {
08516 res = say_and_wait(chan, vms->newmessages, chan->language);
08517 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08518 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08519 }
08520 if (!res && vms->oldmessages)
08521 res = ast_play_and_wait(chan, "vm-and");
08522 }
08523 if (!res && vms->oldmessages) {
08524 if (vms->oldmessages == 1) {
08525 res = ast_play_and_wait(chan, "digits/ett");
08526 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08527 res = res ? res : ast_play_and_wait(chan, "vm-message");
08528 } else {
08529 res = say_and_wait(chan, vms->oldmessages, chan->language);
08530 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08531 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08532 }
08533 }
08534
08535 return res;
08536 }
08537
08538
08539 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08540 {
08541
08542 int res;
08543
08544 res = ast_play_and_wait(chan, "vm-youhave");
08545 if (res)
08546 return res;
08547
08548 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08549 res = ast_play_and_wait(chan, "vm-no");
08550 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08551 return res;
08552 }
08553
08554 if (vms->newmessages) {
08555 if ((vms->newmessages == 1)) {
08556 res = ast_play_and_wait(chan, "digits/1");
08557 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08558 res = res ? res : ast_play_and_wait(chan, "vm-message");
08559 } else {
08560 res = say_and_wait(chan, vms->newmessages, chan->language);
08561 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08562 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08563 }
08564 if (!res && vms->oldmessages)
08565 res = ast_play_and_wait(chan, "vm-and");
08566 }
08567 if (!res && vms->oldmessages) {
08568 if (vms->oldmessages == 1) {
08569 res = ast_play_and_wait(chan, "digits/1");
08570 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08571 res = res ? res : ast_play_and_wait(chan, "vm-message");
08572 } else {
08573 res = say_and_wait(chan, vms->oldmessages, chan->language);
08574 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08575 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08576 }
08577 }
08578
08579 return res;
08580 }
08581
08582
08583 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08584 {
08585
08586 int res;
08587 res = ast_play_and_wait(chan, "vm-youhave");
08588 if (!res) {
08589 if (vms->newmessages) {
08590 if ((vms->newmessages == 1))
08591 res = ast_play_and_wait(chan, "digits/1F");
08592 else
08593 res = say_and_wait(chan, vms->newmessages, chan->language);
08594 if (!res)
08595 res = ast_play_and_wait(chan, "vm-INBOX");
08596 if (vms->oldmessages && !res)
08597 res = ast_play_and_wait(chan, "vm-and");
08598 else if (!res) {
08599 if ((vms->newmessages == 1))
08600 res = ast_play_and_wait(chan, "vm-message");
08601 else
08602 res = ast_play_and_wait(chan, "vm-messages");
08603 }
08604
08605 }
08606 if (!res && vms->oldmessages) {
08607 if (vms->oldmessages == 1)
08608 res = ast_play_and_wait(chan, "digits/1F");
08609 else
08610 res = say_and_wait(chan, vms->oldmessages, chan->language);
08611 if (!res)
08612 res = ast_play_and_wait(chan, "vm-Old");
08613 if (!res) {
08614 if (vms->oldmessages == 1)
08615 res = ast_play_and_wait(chan, "vm-message");
08616 else
08617 res = ast_play_and_wait(chan, "vm-messages");
08618 }
08619 }
08620 if (!res) {
08621 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08622 res = ast_play_and_wait(chan, "vm-no");
08623 if (!res)
08624 res = ast_play_and_wait(chan, "vm-messages");
08625 }
08626 }
08627 }
08628 return res;
08629 }
08630
08631
08632 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08633 {
08634
08635 int res;
08636 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08637 res = ast_play_and_wait(chan, "vm-youhaveno");
08638 if (!res)
08639 res = ast_play_and_wait(chan, "vm-messages");
08640 } else {
08641 res = ast_play_and_wait(chan, "vm-youhave");
08642 }
08643 if (!res) {
08644 if (vms->newmessages) {
08645 if (!res) {
08646 if ((vms->newmessages == 1)) {
08647 res = ast_play_and_wait(chan, "digits/1M");
08648 if (!res)
08649 res = ast_play_and_wait(chan, "vm-message");
08650 if (!res)
08651 res = ast_play_and_wait(chan, "vm-INBOXs");
08652 } else {
08653 res = say_and_wait(chan, vms->newmessages, chan->language);
08654 if (!res)
08655 res = ast_play_and_wait(chan, "vm-messages");
08656 if (!res)
08657 res = ast_play_and_wait(chan, "vm-INBOX");
08658 }
08659 }
08660 if (vms->oldmessages && !res)
08661 res = ast_play_and_wait(chan, "vm-and");
08662 }
08663 if (vms->oldmessages) {
08664 if (!res) {
08665 if (vms->oldmessages == 1) {
08666 res = ast_play_and_wait(chan, "digits/1M");
08667 if (!res)
08668 res = ast_play_and_wait(chan, "vm-message");
08669 if (!res)
08670 res = ast_play_and_wait(chan, "vm-Olds");
08671 } else {
08672 res = say_and_wait(chan, vms->oldmessages, chan->language);
08673 if (!res)
08674 res = ast_play_and_wait(chan, "vm-messages");
08675 if (!res)
08676 res = ast_play_and_wait(chan, "vm-Old");
08677 }
08678 }
08679 }
08680 }
08681 return res;
08682 }
08683
08684
08685 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08686
08687 int res;
08688 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08689 res = ast_play_and_wait(chan, "vm-nomessages");
08690 return res;
08691 } else {
08692 res = ast_play_and_wait(chan, "vm-youhave");
08693 }
08694 if (vms->newmessages) {
08695 if (!res)
08696 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08697 if ((vms->newmessages == 1)) {
08698 if (!res)
08699 res = ast_play_and_wait(chan, "vm-message");
08700 if (!res)
08701 res = ast_play_and_wait(chan, "vm-INBOXs");
08702 } else {
08703 if (!res)
08704 res = ast_play_and_wait(chan, "vm-messages");
08705 if (!res)
08706 res = ast_play_and_wait(chan, "vm-INBOX");
08707 }
08708 if (vms->oldmessages && !res)
08709 res = ast_play_and_wait(chan, "vm-and");
08710 }
08711 if (vms->oldmessages) {
08712 if (!res)
08713 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08714 if (vms->oldmessages == 1) {
08715 if (!res)
08716 res = ast_play_and_wait(chan, "vm-message");
08717 if (!res)
08718 res = ast_play_and_wait(chan, "vm-Olds");
08719 } else {
08720 if (!res)
08721 res = ast_play_and_wait(chan, "vm-messages");
08722 if (!res)
08723 res = ast_play_and_wait(chan, "vm-Old");
08724 }
08725 }
08726 return res;
08727 }
08728
08729
08730 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08731 {
08732
08733 int res;
08734 res = ast_play_and_wait(chan, "vm-youhave");
08735 if (!res) {
08736 if (vms->newmessages) {
08737 res = say_and_wait(chan, vms->newmessages, chan->language);
08738 if (!res)
08739 res = ast_play_and_wait(chan, "vm-INBOX");
08740 if (vms->oldmessages && !res)
08741 res = ast_play_and_wait(chan, "vm-and");
08742 else if (!res) {
08743 if ((vms->newmessages == 1))
08744 res = ast_play_and_wait(chan, "vm-message");
08745 else
08746 res = ast_play_and_wait(chan, "vm-messages");
08747 }
08748
08749 }
08750 if (!res && vms->oldmessages) {
08751 res = say_and_wait(chan, vms->oldmessages, chan->language);
08752 if (!res)
08753 res = ast_play_and_wait(chan, "vm-Old");
08754 if (!res) {
08755 if (vms->oldmessages == 1)
08756 res = ast_play_and_wait(chan, "vm-message");
08757 else
08758 res = ast_play_and_wait(chan, "vm-messages");
08759 }
08760 }
08761 if (!res) {
08762 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08763 res = ast_play_and_wait(chan, "vm-no");
08764 if (!res)
08765 res = ast_play_and_wait(chan, "vm-messages");
08766 }
08767 }
08768 }
08769 return res;
08770 }
08771
08772
08773 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08774 {
08775
08776 int res;
08777 res = ast_play_and_wait(chan, "vm-youhave");
08778 if (!res) {
08779 if (vms->newmessages) {
08780 res = say_and_wait(chan, vms->newmessages, chan->language);
08781 if (!res) {
08782 if (vms->newmessages == 1)
08783 res = ast_play_and_wait(chan, "vm-INBOXs");
08784 else
08785 res = ast_play_and_wait(chan, "vm-INBOX");
08786 }
08787 if (vms->oldmessages && !res)
08788 res = ast_play_and_wait(chan, "vm-and");
08789 else if (!res) {
08790 if ((vms->newmessages == 1))
08791 res = ast_play_and_wait(chan, "vm-message");
08792 else
08793 res = ast_play_and_wait(chan, "vm-messages");
08794 }
08795
08796 }
08797 if (!res && vms->oldmessages) {
08798 res = say_and_wait(chan, vms->oldmessages, chan->language);
08799 if (!res) {
08800 if (vms->oldmessages == 1)
08801 res = ast_play_and_wait(chan, "vm-Olds");
08802 else
08803 res = ast_play_and_wait(chan, "vm-Old");
08804 }
08805 if (!res) {
08806 if (vms->oldmessages == 1)
08807 res = ast_play_and_wait(chan, "vm-message");
08808 else
08809 res = ast_play_and_wait(chan, "vm-messages");
08810 }
08811 }
08812 if (!res) {
08813 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08814 res = ast_play_and_wait(chan, "vm-no");
08815 if (!res)
08816 res = ast_play_and_wait(chan, "vm-messages");
08817 }
08818 }
08819 }
08820 return res;
08821 }
08822
08823
08824 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08825 {
08826
08827 int res;
08828 res = ast_play_and_wait(chan, "vm-youhave");
08829 if (!res) {
08830 if (vms->newmessages) {
08831 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08832 if (!res) {
08833 if ((vms->newmessages == 1)) {
08834 res = ast_play_and_wait(chan, "vm-message");
08835 if (!res)
08836 res = ast_play_and_wait(chan, "vm-INBOXs");
08837 } else {
08838 res = ast_play_and_wait(chan, "vm-messages");
08839 if (!res)
08840 res = ast_play_and_wait(chan, "vm-INBOX");
08841 }
08842 }
08843 if (vms->oldmessages && !res)
08844 res = ast_play_and_wait(chan, "vm-and");
08845 }
08846 if (!res && vms->oldmessages) {
08847 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08848 if (!res) {
08849 if (vms->oldmessages == 1) {
08850 res = ast_play_and_wait(chan, "vm-message");
08851 if (!res)
08852 res = ast_play_and_wait(chan, "vm-Olds");
08853 } else {
08854 res = ast_play_and_wait(chan, "vm-messages");
08855 if (!res)
08856 res = ast_play_and_wait(chan, "vm-Old");
08857 }
08858 }
08859 }
08860 if (!res) {
08861 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08862 res = ast_play_and_wait(chan, "vm-no");
08863 if (!res)
08864 res = ast_play_and_wait(chan, "vm-messages");
08865 }
08866 }
08867 }
08868 return res;
08869 }
08870
08871
08872
08873
08874
08875
08876
08877
08878
08879
08880
08881
08882
08883
08884
08885
08886
08887 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08888 {
08889 int res;
08890 res = ast_play_and_wait(chan, "vm-youhave");
08891 if (!res) {
08892 if (vms->newmessages) {
08893 if (vms->newmessages == 1) {
08894 res = ast_play_and_wait(chan, "digits/jednu");
08895 } else {
08896 res = say_and_wait(chan, vms->newmessages, chan->language);
08897 }
08898 if (!res) {
08899 if ((vms->newmessages == 1))
08900 res = ast_play_and_wait(chan, "vm-novou");
08901 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08902 res = ast_play_and_wait(chan, "vm-nove");
08903 if (vms->newmessages > 4)
08904 res = ast_play_and_wait(chan, "vm-novych");
08905 }
08906 if (vms->oldmessages && !res)
08907 res = ast_play_and_wait(chan, "vm-and");
08908 else if (!res) {
08909 if ((vms->newmessages == 1))
08910 res = ast_play_and_wait(chan, "vm-zpravu");
08911 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08912 res = ast_play_and_wait(chan, "vm-zpravy");
08913 if (vms->newmessages > 4)
08914 res = ast_play_and_wait(chan, "vm-zprav");
08915 }
08916 }
08917 if (!res && vms->oldmessages) {
08918 res = say_and_wait(chan, vms->oldmessages, chan->language);
08919 if (!res) {
08920 if ((vms->oldmessages == 1))
08921 res = ast_play_and_wait(chan, "vm-starou");
08922 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08923 res = ast_play_and_wait(chan, "vm-stare");
08924 if (vms->oldmessages > 4)
08925 res = ast_play_and_wait(chan, "vm-starych");
08926 }
08927 if (!res) {
08928 if ((vms->oldmessages == 1))
08929 res = ast_play_and_wait(chan, "vm-zpravu");
08930 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08931 res = ast_play_and_wait(chan, "vm-zpravy");
08932 if (vms->oldmessages > 4)
08933 res = ast_play_and_wait(chan, "vm-zprav");
08934 }
08935 }
08936 if (!res) {
08937 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08938 res = ast_play_and_wait(chan, "vm-no");
08939 if (!res)
08940 res = ast_play_and_wait(chan, "vm-zpravy");
08941 }
08942 }
08943 }
08944 return res;
08945 }
08946
08947
08948 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08949 {
08950 int res;
08951
08952 res = ast_play_and_wait(chan, "vm-you");
08953
08954 if (!res && vms->newmessages) {
08955 res = ast_play_and_wait(chan, "vm-have");
08956 if (!res)
08957 res = say_and_wait(chan, vms->newmessages, chan->language);
08958 if (!res)
08959 res = ast_play_and_wait(chan, "vm-tong");
08960 if (!res)
08961 res = ast_play_and_wait(chan, "vm-INBOX");
08962 if (vms->oldmessages && !res)
08963 res = ast_play_and_wait(chan, "vm-and");
08964 else if (!res)
08965 res = ast_play_and_wait(chan, "vm-messages");
08966 }
08967 if (!res && vms->oldmessages) {
08968 res = ast_play_and_wait(chan, "vm-have");
08969 if (!res)
08970 res = say_and_wait(chan, vms->oldmessages, chan->language);
08971 if (!res)
08972 res = ast_play_and_wait(chan, "vm-tong");
08973 if (!res)
08974 res = ast_play_and_wait(chan, "vm-Old");
08975 if (!res)
08976 res = ast_play_and_wait(chan, "vm-messages");
08977 }
08978 if (!res && !vms->oldmessages && !vms->newmessages) {
08979 res = ast_play_and_wait(chan, "vm-haveno");
08980 if (!res)
08981 res = ast_play_and_wait(chan, "vm-messages");
08982 }
08983 return res;
08984 }
08985
08986
08987 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
08988 {
08989 int res;
08990
08991
08992 res = ast_play_and_wait(chan, "vm-youhave");
08993 if (!res) {
08994 if (vms->newmessages) {
08995 res = say_and_wait(chan, vms->newmessages, chan->language);
08996 if (!res)
08997 res = ast_play_and_wait(chan, "vm-INBOX");
08998 if (vms->oldmessages && !res)
08999 res = ast_play_and_wait(chan, "vm-and");
09000 }
09001 if (!res && vms->oldmessages) {
09002 res = say_and_wait(chan, vms->oldmessages, chan->language);
09003 if (!res)
09004 res = ast_play_and_wait(chan, "vm-Old");
09005 }
09006 if (!res) {
09007 if (!vms->oldmessages && !vms->newmessages) {
09008 res = ast_play_and_wait(chan, "vm-no");
09009 if (!res)
09010 res = ast_play_and_wait(chan, "vm-message");
09011 }
09012 }
09013 }
09014 return res;
09015 }
09016
09017 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09018 {
09019 char prefile[256];
09020
09021
09022 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09023 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09024 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09025 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09026 ast_play_and_wait(chan, "vm-tempgreetactive");
09027 }
09028 DISPOSE(prefile, -1);
09029 }
09030
09031
09032 if (0) {
09033 return 0;
09034 } else if (!strncasecmp(chan->language, "cs", 2)) {
09035 return vm_intro_cs(chan, vms);
09036 } else if (!strncasecmp(chan->language, "cz", 2)) {
09037 static int deprecation_warning = 0;
09038 if (deprecation_warning++ % 10 == 0) {
09039 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09040 }
09041 return vm_intro_cs(chan, vms);
09042 } else if (!strncasecmp(chan->language, "de", 2)) {
09043 return vm_intro_de(chan, vms);
09044 } else if (!strncasecmp(chan->language, "es", 2)) {
09045 return vm_intro_es(chan, vms);
09046 } else if (!strncasecmp(chan->language, "fr", 2)) {
09047 return vm_intro_fr(chan, vms);
09048 } else if (!strncasecmp(chan->language, "gr", 2)) {
09049 return vm_intro_gr(chan, vms);
09050 } else if (!strncasecmp(chan->language, "he", 2)) {
09051 return vm_intro_he(chan, vms);
09052 } else if (!strncasecmp(chan->language, "it", 2)) {
09053 return vm_intro_it(chan, vms);
09054 } else if (!strncasecmp(chan->language, "nl", 2)) {
09055 return vm_intro_nl(chan, vms);
09056 } else if (!strncasecmp(chan->language, "no", 2)) {
09057 return vm_intro_no(chan, vms);
09058 } else if (!strncasecmp(chan->language, "pl", 2)) {
09059 return vm_intro_pl(chan, vms);
09060 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09061 return vm_intro_pt_BR(chan, vms);
09062 } else if (!strncasecmp(chan->language, "pt", 2)) {
09063 return vm_intro_pt(chan, vms);
09064 } else if (!strncasecmp(chan->language, "ru", 2)) {
09065 return vm_intro_multilang(chan, vms, "n");
09066 } else if (!strncasecmp(chan->language, "se", 2)) {
09067 return vm_intro_se(chan, vms);
09068 } else if (!strncasecmp(chan->language, "ua", 2)) {
09069 return vm_intro_multilang(chan, vms, "n");
09070 } else if (!strncasecmp(chan->language, "vi", 2)) {
09071 return vm_intro_vi(chan, vms);
09072 } else if (!strncasecmp(chan->language, "zh", 2)) {
09073 return vm_intro_zh(chan, vms);
09074 } else {
09075 return vm_intro_en(chan, vms);
09076 }
09077 }
09078
09079 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09080 {
09081 int res = 0;
09082
09083 while (!res) {
09084 if (vms->starting) {
09085 if (vms->lastmsg > -1) {
09086 if (skipadvanced)
09087 res = ast_play_and_wait(chan, "vm-onefor-full");
09088 else
09089 res = ast_play_and_wait(chan, "vm-onefor");
09090 if (!res)
09091 res = vm_play_folder_name(chan, vms->vmbox);
09092 }
09093 if (!res) {
09094 if (skipadvanced)
09095 res = ast_play_and_wait(chan, "vm-opts-full");
09096 else
09097 res = ast_play_and_wait(chan, "vm-opts");
09098 }
09099 } else {
09100
09101 if (skipadvanced) {
09102 res = ast_play_and_wait(chan, "vm-onefor-full");
09103 if (!res)
09104 res = vm_play_folder_name(chan, vms->vmbox);
09105 res = ast_play_and_wait(chan, "vm-opts-full");
09106 }
09107
09108
09109
09110
09111
09112
09113 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09114 res = ast_play_and_wait(chan, "vm-prev");
09115 }
09116 if (!res && !skipadvanced)
09117 res = ast_play_and_wait(chan, "vm-advopts");
09118 if (!res)
09119 res = ast_play_and_wait(chan, "vm-repeat");
09120
09121
09122
09123
09124
09125
09126 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09127 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09128 res = ast_play_and_wait(chan, "vm-next");
09129 }
09130 if (!res) {
09131 if (!vms->deleted[vms->curmsg])
09132 res = ast_play_and_wait(chan, "vm-delete");
09133 else
09134 res = ast_play_and_wait(chan, "vm-undelete");
09135 if (!res)
09136 res = ast_play_and_wait(chan, "vm-toforward");
09137 if (!res)
09138 res = ast_play_and_wait(chan, "vm-savemessage");
09139 }
09140 }
09141 if (!res) {
09142 res = ast_play_and_wait(chan, "vm-helpexit");
09143 }
09144 if (!res)
09145 res = ast_waitfordigit(chan, 6000);
09146 if (!res) {
09147 vms->repeats++;
09148 if (vms->repeats > 2) {
09149 res = 't';
09150 }
09151 }
09152 }
09153 return res;
09154 }
09155
09156 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09157 {
09158 int res = 0;
09159
09160 while (!res) {
09161 if (vms->lastmsg > -1) {
09162 res = ast_play_and_wait(chan, "vm-listen");
09163 if (!res)
09164 res = vm_play_folder_name(chan, vms->vmbox);
09165 if (!res)
09166 res = ast_play_and_wait(chan, "press");
09167 if (!res)
09168 res = ast_play_and_wait(chan, "digits/1");
09169 }
09170 if (!res)
09171 res = ast_play_and_wait(chan, "vm-opts");
09172 if (!res) {
09173 vms->starting = 0;
09174 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09175 }
09176 }
09177 return res;
09178 }
09179
09180 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09181 {
09182 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09183 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09184 } else {
09185 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09186 }
09187 }
09188
09189
09190 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09191 {
09192 int cmd = 0;
09193 int duration = 0;
09194 int tries = 0;
09195 char newpassword[80] = "";
09196 char newpassword2[80] = "";
09197 char prefile[PATH_MAX] = "";
09198 unsigned char buf[256];
09199 int bytes = 0;
09200
09201 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09202 if (ast_adsi_available(chan)) {
09203 bytes += adsi_logo(buf + bytes);
09204 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09205 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09206 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09207 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09208 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09209 }
09210
09211
09212 if (ast_test_flag(vmu, VM_FORCENAME)) {
09213 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09214 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09215 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09216 if (cmd < 0 || cmd == 't' || cmd == '#')
09217 return cmd;
09218 }
09219 }
09220
09221
09222 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09223 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09224 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09225 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09226 if (cmd < 0 || cmd == 't' || cmd == '#')
09227 return cmd;
09228 }
09229
09230 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09231 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09232 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09233 if (cmd < 0 || cmd == 't' || cmd == '#')
09234 return cmd;
09235 }
09236 }
09237
09238
09239
09240
09241
09242 for (;;) {
09243 newpassword[1] = '\0';
09244 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09245 if (cmd == '#')
09246 newpassword[0] = '\0';
09247 if (cmd < 0 || cmd == 't' || cmd == '#')
09248 return cmd;
09249 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09250 if (cmd < 0 || cmd == 't' || cmd == '#')
09251 return cmd;
09252 cmd = check_password(vmu, newpassword);
09253 if (cmd != 0) {
09254 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09255 cmd = ast_play_and_wait(chan, vm_invalid_password);
09256 } else {
09257 newpassword2[1] = '\0';
09258 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09259 if (cmd == '#')
09260 newpassword2[0] = '\0';
09261 if (cmd < 0 || cmd == 't' || cmd == '#')
09262 return cmd;
09263 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09264 if (cmd < 0 || cmd == 't' || cmd == '#')
09265 return cmd;
09266 if (!strcmp(newpassword, newpassword2))
09267 break;
09268 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09269 cmd = ast_play_and_wait(chan, vm_mismatch);
09270 }
09271 if (++tries == 3)
09272 return -1;
09273 if (cmd != 0) {
09274 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09275 }
09276 }
09277 if (pwdchange & PWDCHANGE_INTERNAL)
09278 vm_change_password(vmu, newpassword);
09279 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09280 vm_change_password_shell(vmu, newpassword);
09281
09282 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09283 cmd = ast_play_and_wait(chan, vm_passchanged);
09284
09285 return cmd;
09286 }
09287
09288 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09289 {
09290 int cmd = 0;
09291 int retries = 0;
09292 int duration = 0;
09293 char newpassword[80] = "";
09294 char newpassword2[80] = "";
09295 char prefile[PATH_MAX] = "";
09296 unsigned char buf[256];
09297 int bytes = 0;
09298
09299 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09300 if (ast_adsi_available(chan)) {
09301 bytes += adsi_logo(buf + bytes);
09302 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09303 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09304 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09305 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09306 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09307 }
09308 while ((cmd >= 0) && (cmd != 't')) {
09309 if (cmd)
09310 retries = 0;
09311 switch (cmd) {
09312 case '1':
09313 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09314 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09315 break;
09316 case '2':
09317 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09318 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09319 break;
09320 case '3':
09321 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09322 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09323 break;
09324 case '4':
09325 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09326 break;
09327 case '5':
09328 if (vmu->password[0] == '-') {
09329 cmd = ast_play_and_wait(chan, "vm-no");
09330 break;
09331 }
09332 newpassword[1] = '\0';
09333 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09334 if (cmd == '#')
09335 newpassword[0] = '\0';
09336 else {
09337 if (cmd < 0)
09338 break;
09339 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09340 break;
09341 }
09342 }
09343 cmd = check_password(vmu, newpassword);
09344 if (cmd != 0) {
09345 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09346 cmd = ast_play_and_wait(chan, vm_invalid_password);
09347 if (!cmd) {
09348 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09349 }
09350 break;
09351 }
09352 newpassword2[1] = '\0';
09353 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09354 if (cmd == '#')
09355 newpassword2[0] = '\0';
09356 else {
09357 if (cmd < 0)
09358 break;
09359
09360 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09361 break;
09362 }
09363 }
09364 if (strcmp(newpassword, newpassword2)) {
09365 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09366 cmd = ast_play_and_wait(chan, vm_mismatch);
09367 if (!cmd) {
09368 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09369 }
09370 break;
09371 }
09372
09373 if (pwdchange & PWDCHANGE_INTERNAL) {
09374 vm_change_password(vmu, newpassword);
09375 }
09376 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09377 vm_change_password_shell(vmu, newpassword);
09378 }
09379
09380 ast_debug(1, "User %s set password to %s of length %d\n",
09381 vms->username, newpassword, (int) strlen(newpassword));
09382 cmd = ast_play_and_wait(chan, vm_passchanged);
09383 break;
09384 case '*':
09385 cmd = 't';
09386 break;
09387 default:
09388 cmd = 0;
09389 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09390 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09391 if (ast_fileexists(prefile, NULL, NULL)) {
09392 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09393 }
09394 DISPOSE(prefile, -1);
09395 if (!cmd) {
09396 cmd = ast_play_and_wait(chan, "vm-options");
09397 }
09398 if (!cmd) {
09399 cmd = ast_waitfordigit(chan, 6000);
09400 }
09401 if (!cmd) {
09402 retries++;
09403 }
09404 if (retries > 3) {
09405 cmd = 't';
09406 }
09407 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09408 }
09409 }
09410 if (cmd == 't')
09411 cmd = 0;
09412 return cmd;
09413 }
09414
09415
09416
09417
09418
09419
09420
09421
09422
09423
09424
09425
09426
09427
09428
09429
09430
09431 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09432 {
09433 int cmd = 0;
09434 int retries = 0;
09435 int duration = 0;
09436 char prefile[PATH_MAX] = "";
09437 unsigned char buf[256];
09438 int bytes = 0;
09439
09440 if (ast_adsi_available(chan)) {
09441 bytes += adsi_logo(buf + bytes);
09442 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09443 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09444 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09445 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09446 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09447 }
09448
09449 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09450 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09451 while ((cmd >= 0) && (cmd != 't')) {
09452 if (cmd)
09453 retries = 0;
09454 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09455 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09456 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09457 cmd = 't';
09458 } else {
09459 switch (cmd) {
09460 case '1':
09461 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09462 break;
09463 case '2':
09464 DELETE(prefile, -1, prefile, vmu);
09465 ast_play_and_wait(chan, "vm-tempremoved");
09466 cmd = 't';
09467 break;
09468 case '*':
09469 cmd = 't';
09470 break;
09471 default:
09472 cmd = ast_play_and_wait(chan,
09473 ast_fileexists(prefile, NULL, NULL) > 0 ?
09474 "vm-tempgreeting2" : "vm-tempgreeting");
09475 if (!cmd) {
09476 cmd = ast_waitfordigit(chan, 6000);
09477 }
09478 if (!cmd) {
09479 retries++;
09480 }
09481 if (retries > 3) {
09482 cmd = 't';
09483 }
09484 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09485 }
09486 }
09487 DISPOSE(prefile, -1);
09488 }
09489 if (cmd == 't')
09490 cmd = 0;
09491 return cmd;
09492 }
09493
09494
09495
09496
09497
09498
09499
09500
09501
09502 static int vm_browse_messages_gr(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 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09510 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09511 if (!cmd) {
09512 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09513 cmd = ast_play_and_wait(chan, vms->fn);
09514 }
09515 if (!cmd)
09516 cmd = ast_play_and_wait(chan, "vm-messages");
09517 } else {
09518 if (!cmd)
09519 cmd = ast_play_and_wait(chan, "vm-messages");
09520 if (!cmd) {
09521 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09522 cmd = ast_play_and_wait(chan, vms->fn);
09523 }
09524 }
09525 }
09526 return cmd;
09527 }
09528
09529
09530 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09531 {
09532 int cmd = 0;
09533
09534 if (vms->lastmsg > -1) {
09535 cmd = play_message(chan, vmu, vms);
09536 } else {
09537 if (!strcasecmp(vms->fn, "INBOX")) {
09538 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09539 } else {
09540 cmd = ast_play_and_wait(chan, "vm-nomessages");
09541 }
09542 }
09543 return cmd;
09544 }
09545
09546
09547
09548
09549
09550
09551
09552
09553
09554 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09555 {
09556 int cmd = 0;
09557
09558 if (vms->lastmsg > -1) {
09559 cmd = play_message(chan, vmu, vms);
09560 } else {
09561 cmd = ast_play_and_wait(chan, "vm-youhave");
09562 if (!cmd)
09563 cmd = ast_play_and_wait(chan, "vm-no");
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 if (!cmd)
09569 cmd = ast_play_and_wait(chan, "vm-messages");
09570 }
09571 return cmd;
09572 }
09573
09574
09575
09576
09577
09578
09579
09580
09581
09582 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09583 {
09584 int cmd;
09585
09586 if (vms->lastmsg > -1) {
09587 cmd = play_message(chan, vmu, vms);
09588 } else {
09589 cmd = ast_play_and_wait(chan, "vm-no");
09590 if (!cmd)
09591 cmd = ast_play_and_wait(chan, "vm-message");
09592 if (!cmd) {
09593 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09594 cmd = ast_play_and_wait(chan, vms->fn);
09595 }
09596 }
09597 return cmd;
09598 }
09599
09600
09601
09602
09603
09604
09605
09606
09607
09608 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09609 {
09610 int cmd;
09611
09612 if (vms->lastmsg > -1) {
09613 cmd = play_message(chan, vmu, vms);
09614 } else {
09615 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09616 if (!cmd)
09617 cmd = ast_play_and_wait(chan, "vm-messages");
09618 if (!cmd) {
09619 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09620 cmd = ast_play_and_wait(chan, vms->fn);
09621 }
09622 }
09623 return cmd;
09624 }
09625
09626
09627
09628
09629
09630
09631
09632
09633
09634 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09635 {
09636 int cmd;
09637
09638 if (vms->lastmsg > -1) {
09639 cmd = play_message(chan, vmu, vms);
09640 } else {
09641 cmd = ast_play_and_wait(chan, "vm-no");
09642 if (!cmd) {
09643 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09644 cmd = ast_play_and_wait(chan, vms->fn);
09645 }
09646 if (!cmd)
09647 cmd = ast_play_and_wait(chan, "vm-messages");
09648 }
09649 return cmd;
09650 }
09651
09652
09653
09654
09655
09656
09657
09658
09659
09660 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09661 {
09662 int cmd;
09663
09664 if (vms->lastmsg > -1) {
09665 cmd = play_message(chan, vmu, vms);
09666 } else {
09667 cmd = ast_play_and_wait(chan, "vm-you");
09668 if (!cmd)
09669 cmd = ast_play_and_wait(chan, "vm-haveno");
09670 if (!cmd)
09671 cmd = ast_play_and_wait(chan, "vm-messages");
09672 if (!cmd) {
09673 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09674 cmd = ast_play_and_wait(chan, vms->fn);
09675 }
09676 }
09677 return cmd;
09678 }
09679
09680
09681
09682
09683
09684
09685
09686
09687
09688 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09689 {
09690 int cmd = 0;
09691
09692 if (vms->lastmsg > -1) {
09693 cmd = play_message(chan, vmu, vms);
09694 } else {
09695 cmd = ast_play_and_wait(chan, "vm-no");
09696 if (!cmd) {
09697 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09698 cmd = ast_play_and_wait(chan, vms->fn);
09699 }
09700 }
09701 return cmd;
09702 }
09703
09704
09705
09706
09707
09708
09709
09710
09711
09712
09713
09714
09715 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09716 {
09717 if (!strncasecmp(chan->language, "es", 2)) {
09718 return vm_browse_messages_es(chan, vms, vmu);
09719 } else if (!strncasecmp(chan->language, "gr", 2)) {
09720 return vm_browse_messages_gr(chan, vms, vmu);
09721 } else if (!strncasecmp(chan->language, "he", 2)) {
09722 return vm_browse_messages_he(chan, vms, vmu);
09723 } else if (!strncasecmp(chan->language, "it", 2)) {
09724 return vm_browse_messages_it(chan, vms, vmu);
09725 } else if (!strncasecmp(chan->language, "pt", 2)) {
09726 return vm_browse_messages_pt(chan, vms, vmu);
09727 } else if (!strncasecmp(chan->language, "vi", 2)) {
09728 return vm_browse_messages_vi(chan, vms, vmu);
09729 } else if (!strncasecmp(chan->language, "zh", 2)) {
09730 return vm_browse_messages_zh(chan, vms, vmu);
09731 } else {
09732 return vm_browse_messages_en(chan, vms, vmu);
09733 }
09734 }
09735
09736 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09737 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09738 int skipuser, int max_logins, int silent)
09739 {
09740 int useadsi = 0, valid = 0, logretries = 0;
09741 char password[AST_MAX_EXTENSION]="", *passptr;
09742 struct ast_vm_user vmus, *vmu = NULL;
09743
09744
09745 adsi_begin(chan, &useadsi);
09746 if (!skipuser && useadsi)
09747 adsi_login(chan);
09748 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09749 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09750 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09751 return -1;
09752 }
09753
09754
09755
09756 while (!valid && (logretries < max_logins)) {
09757
09758 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09759 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09760 return -1;
09761 }
09762 if (ast_strlen_zero(mailbox)) {
09763 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09764 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09765 } else {
09766 ast_verb(3, "Username not entered\n");
09767 return -1;
09768 }
09769 } else if (mailbox[0] == '*') {
09770
09771 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09772 if (ast_exists_extension(chan, chan->context, "a", 1,
09773 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09774 return -1;
09775 }
09776 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09777 mailbox[0] = '\0';
09778 }
09779
09780 if (useadsi)
09781 adsi_password(chan);
09782
09783 if (!ast_strlen_zero(prefix)) {
09784 char fullusername[80] = "";
09785 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09786 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09787 ast_copy_string(mailbox, fullusername, mailbox_size);
09788 }
09789
09790 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09791 vmu = find_user(&vmus, context, mailbox);
09792 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09793
09794 password[0] = '\0';
09795 } else {
09796 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09797 if (ast_streamfile(chan, vm_password, chan->language)) {
09798 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09799 return -1;
09800 }
09801 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09802 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09803 return -1;
09804 } else if (password[0] == '*') {
09805
09806 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09807 if (ast_exists_extension(chan, chan->context, "a", 1,
09808 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09809 mailbox[0] = '*';
09810 return -1;
09811 }
09812 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09813 mailbox[0] = '\0';
09814
09815 vmu = NULL;
09816 }
09817 }
09818
09819 if (vmu) {
09820 passptr = vmu->password;
09821 if (passptr[0] == '-') passptr++;
09822 }
09823 if (vmu && !strcmp(passptr, password))
09824 valid++;
09825 else {
09826 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09827 if (!ast_strlen_zero(prefix))
09828 mailbox[0] = '\0';
09829 }
09830 logretries++;
09831 if (!valid) {
09832 if (skipuser || logretries >= max_logins) {
09833 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09834 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09835 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09836 return -1;
09837 }
09838 } else {
09839 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09840 if (useadsi)
09841 adsi_login(chan);
09842 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09843 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09844 return -1;
09845 }
09846 }
09847 if (ast_waitstream(chan, ""))
09848 return -1;
09849 }
09850 }
09851 if (!valid && (logretries >= max_logins)) {
09852 ast_stopstream(chan);
09853 ast_play_and_wait(chan, "vm-goodbye");
09854 return -1;
09855 }
09856 if (vmu && !skipuser) {
09857 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09858 }
09859 return 0;
09860 }
09861
09862 static int vm_execmain(struct ast_channel *chan, const char *data)
09863 {
09864
09865
09866
09867 int res = -1;
09868 int cmd = 0;
09869 int valid = 0;
09870 char prefixstr[80] ="";
09871 char ext_context[256]="";
09872 int box;
09873 int useadsi = 0;
09874 int skipuser = 0;
09875 struct vm_state vms;
09876 struct ast_vm_user *vmu = NULL, vmus;
09877 char *context = NULL;
09878 int silentexit = 0;
09879 struct ast_flags flags = { 0 };
09880 signed char record_gain = 0;
09881 int play_auto = 0;
09882 int play_folder = 0;
09883 int in_urgent = 0;
09884 #ifdef IMAP_STORAGE
09885 int deleted = 0;
09886 #endif
09887
09888
09889 memset(&vms, 0, sizeof(vms));
09890
09891 vms.lastmsg = -1;
09892
09893 memset(&vmus, 0, sizeof(vmus));
09894
09895 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09896 if (chan->_state != AST_STATE_UP) {
09897 ast_debug(1, "Before ast_answer\n");
09898 ast_answer(chan);
09899 }
09900
09901 if (!ast_strlen_zero(data)) {
09902 char *opts[OPT_ARG_ARRAY_SIZE];
09903 char *parse;
09904 AST_DECLARE_APP_ARGS(args,
09905 AST_APP_ARG(argv0);
09906 AST_APP_ARG(argv1);
09907 );
09908
09909 parse = ast_strdupa(data);
09910
09911 AST_STANDARD_APP_ARGS(args, parse);
09912
09913 if (args.argc == 2) {
09914 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09915 return -1;
09916 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09917 int gain;
09918 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09919 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09920 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09921 return -1;
09922 } else {
09923 record_gain = (signed char) gain;
09924 }
09925 } else {
09926 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09927 }
09928 }
09929 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09930 play_auto = 1;
09931 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09932
09933 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09934 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09935 play_folder = -1;
09936 }
09937 } else {
09938 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09939 }
09940 } else {
09941 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09942 }
09943 if (play_folder > 9 || play_folder < 0) {
09944 ast_log(AST_LOG_WARNING,
09945 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09946 opts[OPT_ARG_PLAYFOLDER]);
09947 play_folder = 0;
09948 }
09949 }
09950 } else {
09951
09952 while (*(args.argv0)) {
09953 if (*(args.argv0) == 's')
09954 ast_set_flag(&flags, OPT_SILENT);
09955 else if (*(args.argv0) == 'p')
09956 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09957 else
09958 break;
09959 (args.argv0)++;
09960 }
09961
09962 }
09963
09964 valid = ast_test_flag(&flags, OPT_SILENT);
09965
09966 if ((context = strchr(args.argv0, '@')))
09967 *context++ = '\0';
09968
09969 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09970 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09971 else
09972 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09973
09974 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09975 skipuser++;
09976 else
09977 valid = 0;
09978 }
09979
09980 if (!valid)
09981 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09982
09983 ast_debug(1, "After vm_authenticate\n");
09984
09985 if (vms.username[0] == '*') {
09986 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09987
09988
09989 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
09990 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
09991 res = 0;
09992 goto out;
09993 }
09994 }
09995
09996 if (!res) {
09997 valid = 1;
09998 if (!skipuser)
09999 vmu = &vmus;
10000 } else {
10001 res = 0;
10002 }
10003
10004
10005 adsi_begin(chan, &useadsi);
10006
10007 ast_test_suite_assert(valid);
10008 if (!valid) {
10009 goto out;
10010 }
10011 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10012
10013 #ifdef IMAP_STORAGE
10014 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10015 pthread_setspecific(ts_vmstate.key, &vms);
10016
10017 vms.interactive = 1;
10018 vms.updated = 1;
10019 if (vmu)
10020 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10021 vmstate_insert(&vms);
10022 init_vm_state(&vms);
10023 #endif
10024
10025
10026 if (!ast_strlen_zero(vmu->language))
10027 ast_string_field_set(chan, language, vmu->language);
10028
10029
10030 ast_debug(1, "Before open_mailbox\n");
10031 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10032 if (res < 0)
10033 goto out;
10034 vms.oldmessages = vms.lastmsg + 1;
10035 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10036
10037 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10038 if (res < 0)
10039 goto out;
10040 vms.newmessages = vms.lastmsg + 1;
10041 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10042
10043 in_urgent = 1;
10044 res = open_mailbox(&vms, vmu, 11);
10045 if (res < 0)
10046 goto out;
10047 vms.urgentmessages = vms.lastmsg + 1;
10048 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10049
10050
10051 if (play_auto) {
10052 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10053 if (vms.urgentmessages) {
10054 in_urgent = 1;
10055 res = open_mailbox(&vms, vmu, 11);
10056 } else {
10057 in_urgent = 0;
10058 res = open_mailbox(&vms, vmu, play_folder);
10059 }
10060 if (res < 0)
10061 goto out;
10062
10063
10064 if (vms.lastmsg == -1) {
10065 in_urgent = 0;
10066 cmd = vm_browse_messages(chan, &vms, vmu);
10067 res = 0;
10068 goto out;
10069 }
10070 } else {
10071 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10072
10073 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10074 in_urgent = 0;
10075 play_folder = 1;
10076 if (res < 0)
10077 goto out;
10078 } else if (!vms.urgentmessages && vms.newmessages) {
10079
10080 in_urgent = 0;
10081 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10082 if (res < 0)
10083 goto out;
10084 }
10085 }
10086
10087 if (useadsi)
10088 adsi_status(chan, &vms);
10089 res = 0;
10090
10091
10092 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10093 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10094 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10095 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10096 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10097 if ((cmd == 't') || (cmd == '#')) {
10098
10099 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10100 res = 0;
10101 goto out;
10102 } else if (cmd < 0) {
10103
10104 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10105 res = -1;
10106 goto out;
10107 }
10108 }
10109 #ifdef IMAP_STORAGE
10110 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10111 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10112 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10113 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10114 }
10115 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10116 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10117 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10118 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10119 }
10120 #endif
10121
10122 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10123 if (play_auto) {
10124 cmd = '1';
10125 } else {
10126 cmd = vm_intro(chan, vmu, &vms);
10127 }
10128 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10129
10130 vms.repeats = 0;
10131 vms.starting = 1;
10132 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10133
10134 switch (cmd) {
10135 case '1':
10136 vms.curmsg = 0;
10137
10138 case '5':
10139 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10140 cmd = vm_browse_messages(chan, &vms, vmu);
10141 break;
10142 case '2':
10143 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10144 if (useadsi)
10145 adsi_folders(chan, 0, "Change to folder...");
10146
10147 cmd = get_folder2(chan, "vm-changeto", 0);
10148 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10149 if (cmd == '#') {
10150 cmd = 0;
10151 } else if (cmd > 0) {
10152 cmd = cmd - '0';
10153 res = close_mailbox(&vms, vmu);
10154 if (res == ERROR_LOCK_PATH)
10155 goto out;
10156
10157 if (cmd != 11) in_urgent = 0;
10158 res = open_mailbox(&vms, vmu, cmd);
10159 if (res < 0)
10160 goto out;
10161 play_folder = cmd;
10162 cmd = 0;
10163 }
10164 if (useadsi)
10165 adsi_status2(chan, &vms);
10166
10167 if (!cmd) {
10168 cmd = vm_play_folder_name(chan, vms.vmbox);
10169 }
10170
10171 vms.starting = 1;
10172 break;
10173 case '3':
10174 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10175 cmd = 0;
10176 vms.repeats = 0;
10177 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10178 switch (cmd) {
10179 case '1':
10180 if (vms.lastmsg > -1 && !vms.starting) {
10181 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10182 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
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 '2':
10192 if (!vms.starting)
10193 ast_verb(3, "Callback Requested\n");
10194 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10195 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10196 if (cmd == 9) {
10197 silentexit = 1;
10198 goto out;
10199 } else if (cmd == ERROR_LOCK_PATH) {
10200 res = cmd;
10201 goto out;
10202 }
10203 } else {
10204 cmd = ast_play_and_wait(chan, "vm-sorry");
10205 }
10206 cmd = 't';
10207 break;
10208 case '3':
10209 if (vms.lastmsg > -1 && !vms.starting) {
10210 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10211 if (cmd == ERROR_LOCK_PATH) {
10212 res = cmd;
10213 goto out;
10214 }
10215 } else {
10216 cmd = ast_play_and_wait(chan, "vm-sorry");
10217 }
10218 cmd = 't';
10219 break;
10220 case '4':
10221 if (!ast_strlen_zero(vmu->dialout)) {
10222 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10223 if (cmd == 9) {
10224 silentexit = 1;
10225 goto out;
10226 }
10227 } else {
10228 cmd = ast_play_and_wait(chan, "vm-sorry");
10229 }
10230 cmd = 't';
10231 break;
10232
10233 case '5':
10234 if (ast_test_flag(vmu, VM_SVMAIL)) {
10235 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10236 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10237 res = cmd;
10238 goto out;
10239 }
10240 } else {
10241 cmd = ast_play_and_wait(chan, "vm-sorry");
10242 }
10243 cmd = 't';
10244 break;
10245
10246 case '*':
10247 cmd = 't';
10248 break;
10249
10250 default:
10251 cmd = 0;
10252 if (!vms.starting) {
10253 cmd = ast_play_and_wait(chan, "vm-toreply");
10254 }
10255 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10256 cmd = ast_play_and_wait(chan, "vm-tocallback");
10257 }
10258 if (!cmd && !vms.starting) {
10259 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10260 }
10261 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10262 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10263 }
10264 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10265 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10266 }
10267 if (!cmd) {
10268 cmd = ast_play_and_wait(chan, "vm-starmain");
10269 }
10270 if (!cmd) {
10271 cmd = ast_waitfordigit(chan, 6000);
10272 }
10273 if (!cmd) {
10274 vms.repeats++;
10275 }
10276 if (vms.repeats > 3) {
10277 cmd = 't';
10278 }
10279 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10280 }
10281 }
10282 if (cmd == 't') {
10283 cmd = 0;
10284 vms.repeats = 0;
10285 }
10286 break;
10287 case '4':
10288 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10289 if (vms.curmsg > 0) {
10290 vms.curmsg--;
10291 cmd = play_message(chan, vmu, &vms);
10292 } else {
10293
10294
10295
10296
10297 if (in_urgent == 0 && vms.urgentmessages > 0) {
10298
10299 in_urgent = 1;
10300 res = close_mailbox(&vms, vmu);
10301 if (res == ERROR_LOCK_PATH)
10302 goto out;
10303 res = open_mailbox(&vms, vmu, 11);
10304 if (res < 0)
10305 goto out;
10306 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10307 vms.curmsg = vms.lastmsg;
10308 if (vms.lastmsg < 0) {
10309 cmd = ast_play_and_wait(chan, "vm-nomore");
10310 }
10311 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10312 vms.curmsg = vms.lastmsg;
10313 cmd = play_message(chan, vmu, &vms);
10314 } else {
10315 cmd = ast_play_and_wait(chan, "vm-nomore");
10316 }
10317 }
10318 break;
10319 case '6':
10320 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10321 if (vms.curmsg < vms.lastmsg) {
10322 vms.curmsg++;
10323 cmd = play_message(chan, vmu, &vms);
10324 } else {
10325 if (in_urgent && vms.newmessages > 0) {
10326
10327
10328
10329
10330 in_urgent = 0;
10331 res = close_mailbox(&vms, vmu);
10332 if (res == ERROR_LOCK_PATH)
10333 goto out;
10334 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10335 if (res < 0)
10336 goto out;
10337 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10338 vms.curmsg = -1;
10339 if (vms.lastmsg < 0) {
10340 cmd = ast_play_and_wait(chan, "vm-nomore");
10341 }
10342 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10343 vms.curmsg = 0;
10344 cmd = play_message(chan, vmu, &vms);
10345 } else {
10346 cmd = ast_play_and_wait(chan, "vm-nomore");
10347 }
10348 }
10349 break;
10350 case '7':
10351 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10352 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10353 if (useadsi)
10354 adsi_delete(chan, &vms);
10355 if (vms.deleted[vms.curmsg]) {
10356 if (play_folder == 0) {
10357 if (in_urgent) {
10358 vms.urgentmessages--;
10359 } else {
10360 vms.newmessages--;
10361 }
10362 }
10363 else if (play_folder == 1)
10364 vms.oldmessages--;
10365 cmd = ast_play_and_wait(chan, "vm-deleted");
10366 } else {
10367 if (play_folder == 0) {
10368 if (in_urgent) {
10369 vms.urgentmessages++;
10370 } else {
10371 vms.newmessages++;
10372 }
10373 }
10374 else if (play_folder == 1)
10375 vms.oldmessages++;
10376 cmd = ast_play_and_wait(chan, "vm-undeleted");
10377 }
10378 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10379 if (vms.curmsg < vms.lastmsg) {
10380 vms.curmsg++;
10381 cmd = play_message(chan, vmu, &vms);
10382 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10383 vms.curmsg = 0;
10384 cmd = play_message(chan, vmu, &vms);
10385 } else {
10386
10387
10388
10389
10390 if (in_urgent == 1) {
10391
10392 in_urgent = 0;
10393 res = close_mailbox(&vms, vmu);
10394 if (res == ERROR_LOCK_PATH)
10395 goto out;
10396 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10397 if (res < 0)
10398 goto out;
10399 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10400 vms.curmsg = -1;
10401 if (vms.lastmsg < 0) {
10402 cmd = ast_play_and_wait(chan, "vm-nomore");
10403 }
10404 } else {
10405 cmd = ast_play_and_wait(chan, "vm-nomore");
10406 }
10407 }
10408 }
10409 } else
10410 cmd = 0;
10411 #ifdef IMAP_STORAGE
10412 deleted = 1;
10413 #endif
10414 break;
10415
10416 case '8':
10417 if (vms.lastmsg > -1) {
10418 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10419 if (cmd == ERROR_LOCK_PATH) {
10420 res = cmd;
10421 goto out;
10422 }
10423 } else {
10424
10425
10426
10427
10428 if (in_urgent == 1 && vms.newmessages > 0) {
10429
10430 in_urgent = 0;
10431 res = close_mailbox(&vms, vmu);
10432 if (res == ERROR_LOCK_PATH)
10433 goto out;
10434 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10435 if (res < 0)
10436 goto out;
10437 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10438 vms.curmsg = -1;
10439 if (vms.lastmsg < 0) {
10440 cmd = ast_play_and_wait(chan, "vm-nomore");
10441 }
10442 } else {
10443 cmd = ast_play_and_wait(chan, "vm-nomore");
10444 }
10445 }
10446 break;
10447 case '9':
10448 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10449 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10450
10451 cmd = 0;
10452 break;
10453 }
10454 if (useadsi)
10455 adsi_folders(chan, 1, "Save to folder...");
10456 cmd = get_folder2(chan, "vm-savefolder", 1);
10457 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10458 box = 0;
10459 if (cmd == '#') {
10460 cmd = 0;
10461 break;
10462 } else if (cmd > 0) {
10463 box = cmd = cmd - '0';
10464 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10465 if (cmd == ERROR_LOCK_PATH) {
10466 res = cmd;
10467 goto out;
10468 #ifndef IMAP_STORAGE
10469 } else if (!cmd) {
10470 vms.deleted[vms.curmsg] = 1;
10471 #endif
10472 } else {
10473 vms.deleted[vms.curmsg] = 0;
10474 vms.heard[vms.curmsg] = 0;
10475 }
10476 }
10477 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10478 if (useadsi)
10479 adsi_message(chan, &vms);
10480 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10481 if (!cmd) {
10482 cmd = ast_play_and_wait(chan, "vm-message");
10483 if (!cmd)
10484 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10485 if (!cmd)
10486 cmd = ast_play_and_wait(chan, "vm-savedto");
10487 if (!cmd)
10488 cmd = vm_play_folder_name(chan, vms.fn);
10489 } else {
10490 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10491 }
10492 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10493 if (vms.curmsg < vms.lastmsg) {
10494 vms.curmsg++;
10495 cmd = play_message(chan, vmu, &vms);
10496 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10497 vms.curmsg = 0;
10498 cmd = play_message(chan, vmu, &vms);
10499 } else {
10500
10501
10502
10503
10504 if (in_urgent == 1 && vms.newmessages > 0) {
10505
10506 in_urgent = 0;
10507 res = close_mailbox(&vms, vmu);
10508 if (res == ERROR_LOCK_PATH)
10509 goto out;
10510 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10511 if (res < 0)
10512 goto out;
10513 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10514 vms.curmsg = -1;
10515 if (vms.lastmsg < 0) {
10516 cmd = ast_play_and_wait(chan, "vm-nomore");
10517 }
10518 } else {
10519 cmd = ast_play_and_wait(chan, "vm-nomore");
10520 }
10521 }
10522 }
10523 break;
10524 case '*':
10525 if (!vms.starting) {
10526 cmd = ast_play_and_wait(chan, "vm-onefor");
10527 if (!strncasecmp(chan->language, "he", 2)) {
10528 cmd = ast_play_and_wait(chan, "vm-for");
10529 }
10530 if (!cmd)
10531 cmd = vm_play_folder_name(chan, vms.vmbox);
10532 if (!cmd)
10533 cmd = ast_play_and_wait(chan, "vm-opts");
10534 if (!cmd)
10535 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10536 } else
10537 cmd = 0;
10538 break;
10539 case '0':
10540 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10541 if (useadsi)
10542 adsi_status(chan, &vms);
10543 break;
10544 default:
10545 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10546 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10547 break;
10548 }
10549 }
10550 if ((cmd == 't') || (cmd == '#')) {
10551
10552 res = 0;
10553 } else {
10554
10555 res = -1;
10556 }
10557
10558 out:
10559 if (res > -1) {
10560 ast_stopstream(chan);
10561 adsi_goodbye(chan);
10562 if (valid && res != OPERATOR_EXIT) {
10563 if (silentexit)
10564 res = ast_play_and_wait(chan, "vm-dialout");
10565 else
10566 res = ast_play_and_wait(chan, "vm-goodbye");
10567 }
10568 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10569 res = 0;
10570 }
10571 if (useadsi)
10572 ast_adsi_unload_session(chan);
10573 }
10574 if (vmu)
10575 close_mailbox(&vms, vmu);
10576 if (valid) {
10577 int new = 0, old = 0, urgent = 0;
10578 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10579 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10580
10581 run_externnotify(vmu->context, vmu->mailbox, NULL);
10582 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10583 queue_mwi_event(ext_context, urgent, new, old);
10584 }
10585 #ifdef IMAP_STORAGE
10586
10587 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10588 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10589 ast_mutex_lock(&vms.lock);
10590 #ifdef HAVE_IMAP_TK2006
10591 if (LEVELUIDPLUS (vms.mailstream)) {
10592 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10593 } else
10594 #endif
10595 mail_expunge(vms.mailstream);
10596 ast_mutex_unlock(&vms.lock);
10597 }
10598
10599
10600 if (vmu) {
10601 vmstate_delete(&vms);
10602 }
10603 #endif
10604 if (vmu)
10605 free_user(vmu);
10606
10607 #ifdef IMAP_STORAGE
10608 pthread_setspecific(ts_vmstate.key, NULL);
10609 #endif
10610 return res;
10611 }
10612
10613 static int vm_exec(struct ast_channel *chan, const char *data)
10614 {
10615 int res = 0;
10616 char *tmp;
10617 struct leave_vm_options leave_options;
10618 struct ast_flags flags = { 0 };
10619 char *opts[OPT_ARG_ARRAY_SIZE];
10620 AST_DECLARE_APP_ARGS(args,
10621 AST_APP_ARG(argv0);
10622 AST_APP_ARG(argv1);
10623 );
10624
10625 memset(&leave_options, 0, sizeof(leave_options));
10626
10627 if (chan->_state != AST_STATE_UP)
10628 ast_answer(chan);
10629
10630 if (!ast_strlen_zero(data)) {
10631 tmp = ast_strdupa(data);
10632 AST_STANDARD_APP_ARGS(args, tmp);
10633 if (args.argc == 2) {
10634 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10635 return -1;
10636 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10637 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10638 int gain;
10639
10640 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10641 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10642 return -1;
10643 } else {
10644 leave_options.record_gain = (signed char) gain;
10645 }
10646 }
10647 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10648 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10649 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10650 }
10651 }
10652 } else {
10653 char temp[256];
10654 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10655 if (res < 0)
10656 return res;
10657 if (ast_strlen_zero(temp))
10658 return 0;
10659 args.argv0 = ast_strdupa(temp);
10660 }
10661
10662 res = leave_voicemail(chan, args.argv0, &leave_options);
10663 if (res == 't') {
10664 ast_play_and_wait(chan, "vm-goodbye");
10665 res = 0;
10666 }
10667
10668 if (res == OPERATOR_EXIT) {
10669 res = 0;
10670 }
10671
10672 if (res == ERROR_LOCK_PATH) {
10673 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10674 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10675 res = 0;
10676 }
10677
10678 return res;
10679 }
10680
10681 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10682 {
10683 struct ast_vm_user *vmu;
10684
10685 if (!ast_strlen_zero(box) && box[0] == '*') {
10686 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10687 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10688 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10689 "\n\tand will be ignored.\n", box, context);
10690 return NULL;
10691 }
10692
10693 AST_LIST_TRAVERSE(&users, vmu, list) {
10694 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10695 if (strcasecmp(vmu->context, context)) {
10696 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10697 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10698 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10699 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10700 }
10701 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10702 return NULL;
10703 }
10704 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10705 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10706 return NULL;
10707 }
10708 }
10709
10710 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10711 return NULL;
10712
10713 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10714 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10715
10716 AST_LIST_INSERT_TAIL(&users, vmu, list);
10717
10718 return vmu;
10719 }
10720
10721 static int append_mailbox(const char *context, const char *box, const char *data)
10722 {
10723
10724 char *tmp;
10725 char *stringp;
10726 char *s;
10727 struct ast_vm_user *vmu;
10728 char *mailbox_full;
10729 int new = 0, old = 0, urgent = 0;
10730 char secretfn[PATH_MAX] = "";
10731
10732 tmp = ast_strdupa(data);
10733
10734 if (!(vmu = find_or_create(context, box)))
10735 return -1;
10736
10737 populate_defaults(vmu);
10738
10739 stringp = tmp;
10740 if ((s = strsep(&stringp, ","))) {
10741 if (!ast_strlen_zero(s) && s[0] == '*') {
10742 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10743 "\n\tmust be reset in voicemail.conf.\n", box);
10744 }
10745
10746 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10747 }
10748 if (stringp && (s = strsep(&stringp, ","))) {
10749 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10750 }
10751 if (stringp && (s = strsep(&stringp, ","))) {
10752 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10753 }
10754 if (stringp && (s = strsep(&stringp, ","))) {
10755 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10756 }
10757 if (stringp && (s = strsep(&stringp, ","))) {
10758 apply_options(vmu, s);
10759 }
10760
10761 switch (vmu->passwordlocation) {
10762 case OPT_PWLOC_SPOOLDIR:
10763 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10764 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10765 }
10766
10767 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10768 strcpy(mailbox_full, box);
10769 strcat(mailbox_full, "@");
10770 strcat(mailbox_full, context);
10771
10772 inboxcount2(mailbox_full, &urgent, &new, &old);
10773 queue_mwi_event(mailbox_full, urgent, new, old);
10774
10775 return 0;
10776 }
10777
10778 AST_TEST_DEFINE(test_voicemail_vmuser)
10779 {
10780 int res = 0;
10781 struct ast_vm_user *vmu;
10782
10783 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10784 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10785 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10786 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10787 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10788 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10789 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10790 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10791 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10792 #ifdef IMAP_STORAGE
10793 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10794 "imapfolder=INBOX|imapvmshareid=6000";
10795 #endif
10796
10797 switch (cmd) {
10798 case TEST_INIT:
10799 info->name = "vmuser";
10800 info->category = "/apps/app_voicemail/";
10801 info->summary = "Vmuser unit test";
10802 info->description =
10803 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10804 return AST_TEST_NOT_RUN;
10805 case TEST_EXECUTE:
10806 break;
10807 }
10808
10809 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10810 return AST_TEST_NOT_RUN;
10811 }
10812 ast_set_flag(vmu, VM_ALLOCED);
10813 populate_defaults(vmu);
10814
10815 apply_options(vmu, options_string);
10816
10817 if (!ast_test_flag(vmu, VM_ATTACH)) {
10818 ast_test_status_update(test, "Parse failure for attach option\n");
10819 res = 1;
10820 }
10821 if (strcasecmp(vmu->attachfmt, "wav49")) {
10822 ast_test_status_update(test, "Parse failure for attachftm option\n");
10823 res = 1;
10824 }
10825 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10826 ast_test_status_update(test, "Parse failure for serveremail option\n");
10827 res = 1;
10828 }
10829 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10830 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10831 res = 1;
10832 }
10833 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10834 ast_test_status_update(test, "Parse failure for emailbody option\n");
10835 res = 1;
10836 }
10837 if (strcasecmp(vmu->zonetag, "central")) {
10838 ast_test_status_update(test, "Parse failure for tz option\n");
10839 res = 1;
10840 }
10841 if (!ast_test_flag(vmu, VM_DELETE)) {
10842 ast_test_status_update(test, "Parse failure for delete option\n");
10843 res = 1;
10844 }
10845 if (!ast_test_flag(vmu, VM_SAYCID)) {
10846 ast_test_status_update(test, "Parse failure for saycid option\n");
10847 res = 1;
10848 }
10849 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10850 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10851 res = 1;
10852 }
10853 if (!ast_test_flag(vmu, VM_REVIEW)) {
10854 ast_test_status_update(test, "Parse failure for review option\n");
10855 res = 1;
10856 }
10857 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10858 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10859 res = 1;
10860 }
10861 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10862 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10863 res = 1;
10864 }
10865 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10866 ast_test_status_update(test, "Parse failure for operator option\n");
10867 res = 1;
10868 }
10869 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10870 ast_test_status_update(test, "Parse failure for envelope option\n");
10871 res = 1;
10872 }
10873 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10874 ast_test_status_update(test, "Parse failure for moveheard option\n");
10875 res = 1;
10876 }
10877 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10878 ast_test_status_update(test, "Parse failure for sayduration option\n");
10879 res = 1;
10880 }
10881 if (vmu->saydurationm != 5) {
10882 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10883 res = 1;
10884 }
10885 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10886 ast_test_status_update(test, "Parse failure for forcename option\n");
10887 res = 1;
10888 }
10889 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10890 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10891 res = 1;
10892 }
10893 if (strcasecmp(vmu->callback, "somecontext")) {
10894 ast_test_status_update(test, "Parse failure for callbacks option\n");
10895 res = 1;
10896 }
10897 if (strcasecmp(vmu->dialout, "somecontext2")) {
10898 ast_test_status_update(test, "Parse failure for dialout option\n");
10899 res = 1;
10900 }
10901 if (strcasecmp(vmu->exit, "somecontext3")) {
10902 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10903 res = 1;
10904 }
10905 if (vmu->minsecs != 10) {
10906 ast_test_status_update(test, "Parse failure for minsecs option\n");
10907 res = 1;
10908 }
10909 if (vmu->maxsecs != 100) {
10910 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10911 res = 1;
10912 }
10913 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10914 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10915 res = 1;
10916 }
10917 if (vmu->maxdeletedmsg != 50) {
10918 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10919 res = 1;
10920 }
10921 if (vmu->volgain != 1.3) {
10922 ast_test_status_update(test, "Parse failure for volgain option\n");
10923 res = 1;
10924 }
10925 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10926 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10927 res = 1;
10928 }
10929 #ifdef IMAP_STORAGE
10930 apply_options(vmu, option_string2);
10931
10932 if (strcasecmp(vmu->imapuser, "imapuser")) {
10933 ast_test_status_update(test, "Parse failure for imapuser option\n");
10934 res = 1;
10935 }
10936 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10937 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10938 res = 1;
10939 }
10940 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10941 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10942 res = 1;
10943 }
10944 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10945 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10946 res = 1;
10947 }
10948 #endif
10949
10950 free_user(vmu);
10951 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10952 }
10953
10954 static int vm_box_exists(struct ast_channel *chan, const char *data)
10955 {
10956 struct ast_vm_user svm;
10957 char *context, *box;
10958 AST_DECLARE_APP_ARGS(args,
10959 AST_APP_ARG(mbox);
10960 AST_APP_ARG(options);
10961 );
10962 static int dep_warning = 0;
10963
10964 if (ast_strlen_zero(data)) {
10965 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10966 return -1;
10967 }
10968
10969 if (!dep_warning) {
10970 dep_warning = 1;
10971 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10972 }
10973
10974 box = ast_strdupa(data);
10975
10976 AST_STANDARD_APP_ARGS(args, box);
10977
10978 if (args.options) {
10979 }
10980
10981 if ((context = strchr(args.mbox, '@'))) {
10982 *context = '\0';
10983 context++;
10984 }
10985
10986 if (find_user(&svm, context, args.mbox)) {
10987 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
10988 } else
10989 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
10990
10991 return 0;
10992 }
10993
10994 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
10995 {
10996 struct ast_vm_user svm;
10997 AST_DECLARE_APP_ARGS(arg,
10998 AST_APP_ARG(mbox);
10999 AST_APP_ARG(context);
11000 );
11001
11002 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11003
11004 if (ast_strlen_zero(arg.mbox)) {
11005 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11006 return -1;
11007 }
11008
11009 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11010 return 0;
11011 }
11012
11013 static struct ast_custom_function mailbox_exists_acf = {
11014 .name = "MAILBOX_EXISTS",
11015 .read = acf_mailbox_exists,
11016 };
11017
11018 static int vmauthenticate(struct ast_channel *chan, const char *data)
11019 {
11020 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11021 struct ast_vm_user vmus;
11022 char *options = NULL;
11023 int silent = 0, skipuser = 0;
11024 int res = -1;
11025
11026 if (data) {
11027 s = ast_strdupa(data);
11028 user = strsep(&s, ",");
11029 options = strsep(&s, ",");
11030 if (user) {
11031 s = user;
11032 user = strsep(&s, "@");
11033 context = strsep(&s, "");
11034 if (!ast_strlen_zero(user))
11035 skipuser++;
11036 ast_copy_string(mailbox, user, sizeof(mailbox));
11037 }
11038 }
11039
11040 if (options) {
11041 silent = (strchr(options, 's')) != NULL;
11042 }
11043
11044 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11045 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11046 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11047 ast_play_and_wait(chan, "auth-thankyou");
11048 res = 0;
11049 } else if (mailbox[0] == '*') {
11050
11051 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11052 res = 0;
11053 }
11054 }
11055
11056 return res;
11057 }
11058
11059 static char *show_users_realtime(int fd, const char *context)
11060 {
11061 struct ast_config *cfg;
11062 const char *cat = NULL;
11063
11064 if (!(cfg = ast_load_realtime_multientry("voicemail",
11065 "context", context, SENTINEL))) {
11066 return CLI_FAILURE;
11067 }
11068
11069 ast_cli(fd,
11070 "\n"
11071 "=============================================================\n"
11072 "=== Configured Voicemail Users ==============================\n"
11073 "=============================================================\n"
11074 "===\n");
11075
11076 while ((cat = ast_category_browse(cfg, cat))) {
11077 struct ast_variable *var = NULL;
11078 ast_cli(fd,
11079 "=== Mailbox ...\n"
11080 "===\n");
11081 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11082 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11083 ast_cli(fd,
11084 "===\n"
11085 "=== ---------------------------------------------------------\n"
11086 "===\n");
11087 }
11088
11089 ast_cli(fd,
11090 "=============================================================\n"
11091 "\n");
11092
11093 ast_config_destroy(cfg);
11094
11095 return CLI_SUCCESS;
11096 }
11097
11098 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11099 {
11100 int which = 0;
11101 int wordlen;
11102 struct ast_vm_user *vmu;
11103 const char *context = "";
11104
11105
11106 if (pos > 4)
11107 return NULL;
11108 if (pos == 3)
11109 return (state == 0) ? ast_strdup("for") : NULL;
11110 wordlen = strlen(word);
11111 AST_LIST_TRAVERSE(&users, vmu, list) {
11112 if (!strncasecmp(word, vmu->context, wordlen)) {
11113 if (context && strcmp(context, vmu->context) && ++which > state)
11114 return ast_strdup(vmu->context);
11115
11116 context = vmu->context;
11117 }
11118 }
11119 return NULL;
11120 }
11121
11122
11123 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11124 {
11125 struct ast_vm_user *vmu;
11126 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11127 const char *context = NULL;
11128 int users_counter = 0;
11129
11130 switch (cmd) {
11131 case CLI_INIT:
11132 e->command = "voicemail show users";
11133 e->usage =
11134 "Usage: voicemail show users [for <context>]\n"
11135 " Lists all mailboxes currently set up\n";
11136 return NULL;
11137 case CLI_GENERATE:
11138 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11139 }
11140
11141 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11142 return CLI_SHOWUSAGE;
11143 if (a->argc == 5) {
11144 if (strcmp(a->argv[3],"for"))
11145 return CLI_SHOWUSAGE;
11146 context = a->argv[4];
11147 }
11148
11149 if (ast_check_realtime("voicemail")) {
11150 if (!context) {
11151 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11152 return CLI_SHOWUSAGE;
11153 }
11154 return show_users_realtime(a->fd, context);
11155 }
11156
11157 AST_LIST_LOCK(&users);
11158 if (AST_LIST_EMPTY(&users)) {
11159 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11160 AST_LIST_UNLOCK(&users);
11161 return CLI_FAILURE;
11162 }
11163 if (a->argc == 3)
11164 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11165 else {
11166 int count = 0;
11167 AST_LIST_TRAVERSE(&users, vmu, list) {
11168 if (!strcmp(context, vmu->context))
11169 count++;
11170 }
11171 if (count) {
11172 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11173 } else {
11174 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11175 AST_LIST_UNLOCK(&users);
11176 return CLI_FAILURE;
11177 }
11178 }
11179 AST_LIST_TRAVERSE(&users, vmu, list) {
11180 int newmsgs = 0, oldmsgs = 0;
11181 char count[12], tmp[256] = "";
11182
11183 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
11184 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11185 inboxcount(tmp, &newmsgs, &oldmsgs);
11186 snprintf(count, sizeof(count), "%d", newmsgs);
11187 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11188 users_counter++;
11189 }
11190 }
11191 AST_LIST_UNLOCK(&users);
11192 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11193 return CLI_SUCCESS;
11194 }
11195
11196
11197 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11198 {
11199 struct vm_zone *zone;
11200 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11201 char *res = CLI_SUCCESS;
11202
11203 switch (cmd) {
11204 case CLI_INIT:
11205 e->command = "voicemail show zones";
11206 e->usage =
11207 "Usage: voicemail show zones\n"
11208 " Lists zone message formats\n";
11209 return NULL;
11210 case CLI_GENERATE:
11211 return NULL;
11212 }
11213
11214 if (a->argc != 3)
11215 return CLI_SHOWUSAGE;
11216
11217 AST_LIST_LOCK(&zones);
11218 if (!AST_LIST_EMPTY(&zones)) {
11219 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11220 AST_LIST_TRAVERSE(&zones, zone, list) {
11221 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11222 }
11223 } else {
11224 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11225 res = CLI_FAILURE;
11226 }
11227 AST_LIST_UNLOCK(&zones);
11228
11229 return res;
11230 }
11231
11232
11233 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11234 {
11235 switch (cmd) {
11236 case CLI_INIT:
11237 e->command = "voicemail reload";
11238 e->usage =
11239 "Usage: voicemail reload\n"
11240 " Reload voicemail configuration\n";
11241 return NULL;
11242 case CLI_GENERATE:
11243 return NULL;
11244 }
11245
11246 if (a->argc != 2)
11247 return CLI_SHOWUSAGE;
11248
11249 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11250 load_config(1);
11251
11252 return CLI_SUCCESS;
11253 }
11254
11255 static struct ast_cli_entry cli_voicemail[] = {
11256 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11257 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11258 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11259 };
11260
11261 #ifdef IMAP_STORAGE
11262 #define DATA_EXPORT_VM_USERS(USER) \
11263 USER(ast_vm_user, context, AST_DATA_STRING) \
11264 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11265 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11266 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11267 USER(ast_vm_user, email, AST_DATA_STRING) \
11268 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11269 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11270 USER(ast_vm_user, pager, AST_DATA_STRING) \
11271 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11272 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11273 USER(ast_vm_user, language, AST_DATA_STRING) \
11274 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11275 USER(ast_vm_user, callback, AST_DATA_STRING) \
11276 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11277 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11278 USER(ast_vm_user, exit, AST_DATA_STRING) \
11279 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11280 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11281 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11282 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11283 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11284 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11285 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11286 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11287 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11288 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11289 #else
11290 #define DATA_EXPORT_VM_USERS(USER) \
11291 USER(ast_vm_user, context, AST_DATA_STRING) \
11292 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11293 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11294 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11295 USER(ast_vm_user, email, AST_DATA_STRING) \
11296 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11297 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11298 USER(ast_vm_user, pager, AST_DATA_STRING) \
11299 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11300 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11301 USER(ast_vm_user, language, AST_DATA_STRING) \
11302 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11303 USER(ast_vm_user, callback, AST_DATA_STRING) \
11304 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11305 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11306 USER(ast_vm_user, exit, AST_DATA_STRING) \
11307 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11308 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11309 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11310 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11311 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11312 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11313 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11314 #endif
11315
11316 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11317
11318 #define DATA_EXPORT_VM_ZONES(ZONE) \
11319 ZONE(vm_zone, name, AST_DATA_STRING) \
11320 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11321 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11322
11323 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11324
11325
11326
11327
11328
11329
11330
11331
11332 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11333 struct ast_data *data_root, struct ast_vm_user *user)
11334 {
11335 struct ast_data *data_user, *data_zone;
11336 struct ast_data *data_state;
11337 struct vm_zone *zone = NULL;
11338 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11339 char ext_context[256] = "";
11340
11341 data_user = ast_data_add_node(data_root, "user");
11342 if (!data_user) {
11343 return -1;
11344 }
11345
11346 ast_data_add_structure(ast_vm_user, data_user, user);
11347
11348 AST_LIST_LOCK(&zones);
11349 AST_LIST_TRAVERSE(&zones, zone, list) {
11350 if (!strcmp(zone->name, user->zonetag)) {
11351 break;
11352 }
11353 }
11354 AST_LIST_UNLOCK(&zones);
11355
11356
11357 data_state = ast_data_add_node(data_user, "state");
11358 if (!data_state) {
11359 return -1;
11360 }
11361 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11362 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11363 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11364 ast_data_add_int(data_state, "newmsg", newmsg);
11365 ast_data_add_int(data_state, "oldmsg", oldmsg);
11366
11367 if (zone) {
11368 data_zone = ast_data_add_node(data_user, "zone");
11369 ast_data_add_structure(vm_zone, data_zone, zone);
11370 }
11371
11372 if (!ast_data_search_match(search, data_user)) {
11373 ast_data_remove_node(data_root, data_user);
11374 }
11375
11376 return 0;
11377 }
11378
11379 static int vm_users_data_provider_get(const struct ast_data_search *search,
11380 struct ast_data *data_root)
11381 {
11382 struct ast_vm_user *user;
11383
11384 AST_LIST_LOCK(&users);
11385 AST_LIST_TRAVERSE(&users, user, list) {
11386 vm_users_data_provider_get_helper(search, data_root, user);
11387 }
11388 AST_LIST_UNLOCK(&users);
11389
11390 return 0;
11391 }
11392
11393 static const struct ast_data_handler vm_users_data_provider = {
11394 .version = AST_DATA_HANDLER_VERSION,
11395 .get = vm_users_data_provider_get
11396 };
11397
11398 static const struct ast_data_entry vm_data_providers[] = {
11399 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11400 };
11401
11402 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11403 {
11404 int new = 0, old = 0, urgent = 0;
11405
11406 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11407
11408 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11409 mwi_sub->old_urgent = urgent;
11410 mwi_sub->old_new = new;
11411 mwi_sub->old_old = old;
11412 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11413 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11414 }
11415 }
11416
11417 static void poll_subscribed_mailboxes(void)
11418 {
11419 struct mwi_sub *mwi_sub;
11420
11421 AST_RWLIST_RDLOCK(&mwi_subs);
11422 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11423 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11424 poll_subscribed_mailbox(mwi_sub);
11425 }
11426 }
11427 AST_RWLIST_UNLOCK(&mwi_subs);
11428 }
11429
11430 static void *mb_poll_thread(void *data)
11431 {
11432 while (poll_thread_run) {
11433 struct timespec ts = { 0, };
11434 struct timeval wait;
11435
11436 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11437 ts.tv_sec = wait.tv_sec;
11438 ts.tv_nsec = wait.tv_usec * 1000;
11439
11440 ast_mutex_lock(&poll_lock);
11441 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11442 ast_mutex_unlock(&poll_lock);
11443
11444 if (!poll_thread_run)
11445 break;
11446
11447 poll_subscribed_mailboxes();
11448 }
11449
11450 return NULL;
11451 }
11452
11453 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11454 {
11455 ast_free(mwi_sub);
11456 }
11457
11458 static int handle_unsubscribe(void *datap)
11459 {
11460 struct mwi_sub *mwi_sub;
11461 uint32_t *uniqueid = datap;
11462
11463 AST_RWLIST_WRLOCK(&mwi_subs);
11464 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11465 if (mwi_sub->uniqueid == *uniqueid) {
11466 AST_LIST_REMOVE_CURRENT(entry);
11467 break;
11468 }
11469 }
11470 AST_RWLIST_TRAVERSE_SAFE_END
11471 AST_RWLIST_UNLOCK(&mwi_subs);
11472
11473 if (mwi_sub)
11474 mwi_sub_destroy(mwi_sub);
11475
11476 ast_free(uniqueid);
11477 return 0;
11478 }
11479
11480 static int handle_subscribe(void *datap)
11481 {
11482 unsigned int len;
11483 struct mwi_sub *mwi_sub;
11484 struct mwi_sub_task *p = datap;
11485
11486 len = sizeof(*mwi_sub);
11487 if (!ast_strlen_zero(p->mailbox))
11488 len += strlen(p->mailbox);
11489
11490 if (!ast_strlen_zero(p->context))
11491 len += strlen(p->context) + 1;
11492
11493 if (!(mwi_sub = ast_calloc(1, len)))
11494 return -1;
11495
11496 mwi_sub->uniqueid = p->uniqueid;
11497 if (!ast_strlen_zero(p->mailbox))
11498 strcpy(mwi_sub->mailbox, p->mailbox);
11499
11500 if (!ast_strlen_zero(p->context)) {
11501 strcat(mwi_sub->mailbox, "@");
11502 strcat(mwi_sub->mailbox, p->context);
11503 }
11504
11505 AST_RWLIST_WRLOCK(&mwi_subs);
11506 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11507 AST_RWLIST_UNLOCK(&mwi_subs);
11508 ast_free((void *) p->mailbox);
11509 ast_free((void *) p->context);
11510 ast_free(p);
11511 poll_subscribed_mailbox(mwi_sub);
11512 return 0;
11513 }
11514
11515 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11516 {
11517 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11518 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
11519 return;
11520
11521 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11522 return;
11523
11524 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11525 *uniqueid = u;
11526 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11527 ast_free(uniqueid);
11528 }
11529 }
11530
11531 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11532 {
11533 struct mwi_sub_task *mwist;
11534
11535 if (ast_event_get_type(event) != AST_EVENT_SUB)
11536 return;
11537
11538 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11539 return;
11540
11541 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11542 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11543 return;
11544 }
11545 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11546 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11547 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11548
11549 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11550 ast_free(mwist);
11551 }
11552 }
11553
11554 static void start_poll_thread(void)
11555 {
11556 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11557 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11558 AST_EVENT_IE_END);
11559
11560 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11561 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11562 AST_EVENT_IE_END);
11563
11564 if (mwi_sub_sub)
11565 ast_event_report_subs(mwi_sub_sub);
11566
11567 poll_thread_run = 1;
11568
11569 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
11570 }
11571
11572 static void stop_poll_thread(void)
11573 {
11574 poll_thread_run = 0;
11575
11576 if (mwi_sub_sub) {
11577 ast_event_unsubscribe(mwi_sub_sub);
11578 mwi_sub_sub = NULL;
11579 }
11580
11581 if (mwi_unsub_sub) {
11582 ast_event_unsubscribe(mwi_unsub_sub);
11583 mwi_unsub_sub = NULL;
11584 }
11585
11586 ast_mutex_lock(&poll_lock);
11587 ast_cond_signal(&poll_cond);
11588 ast_mutex_unlock(&poll_lock);
11589
11590 pthread_join(poll_thread, NULL);
11591
11592 poll_thread = AST_PTHREADT_NULL;
11593 }
11594
11595
11596 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11597 {
11598 struct ast_vm_user *vmu = NULL;
11599 const char *id = astman_get_header(m, "ActionID");
11600 char actionid[128] = "";
11601
11602 if (!ast_strlen_zero(id))
11603 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11604
11605 AST_LIST_LOCK(&users);
11606
11607 if (AST_LIST_EMPTY(&users)) {
11608 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11609 AST_LIST_UNLOCK(&users);
11610 return RESULT_SUCCESS;
11611 }
11612
11613 astman_send_ack(s, m, "Voicemail user list will follow");
11614
11615 AST_LIST_TRAVERSE(&users, vmu, list) {
11616 char dirname[256];
11617
11618 #ifdef IMAP_STORAGE
11619 int new, old;
11620 inboxcount(vmu->mailbox, &new, &old);
11621 #endif
11622
11623 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11624 astman_append(s,
11625 "%s"
11626 "Event: VoicemailUserEntry\r\n"
11627 "VMContext: %s\r\n"
11628 "VoiceMailbox: %s\r\n"
11629 "Fullname: %s\r\n"
11630 "Email: %s\r\n"
11631 "Pager: %s\r\n"
11632 "ServerEmail: %s\r\n"
11633 "MailCommand: %s\r\n"
11634 "Language: %s\r\n"
11635 "TimeZone: %s\r\n"
11636 "Callback: %s\r\n"
11637 "Dialout: %s\r\n"
11638 "UniqueID: %s\r\n"
11639 "ExitContext: %s\r\n"
11640 "SayDurationMinimum: %d\r\n"
11641 "SayEnvelope: %s\r\n"
11642 "SayCID: %s\r\n"
11643 "AttachMessage: %s\r\n"
11644 "AttachmentFormat: %s\r\n"
11645 "DeleteMessage: %s\r\n"
11646 "VolumeGain: %.2f\r\n"
11647 "CanReview: %s\r\n"
11648 "CallOperator: %s\r\n"
11649 "MaxMessageCount: %d\r\n"
11650 "MaxMessageLength: %d\r\n"
11651 "NewMessageCount: %d\r\n"
11652 #ifdef IMAP_STORAGE
11653 "OldMessageCount: %d\r\n"
11654 "IMAPUser: %s\r\n"
11655 #endif
11656 "\r\n",
11657 actionid,
11658 vmu->context,
11659 vmu->mailbox,
11660 vmu->fullname,
11661 vmu->email,
11662 vmu->pager,
11663 vmu->serveremail,
11664 vmu->mailcmd,
11665 vmu->language,
11666 vmu->zonetag,
11667 vmu->callback,
11668 vmu->dialout,
11669 vmu->uniqueid,
11670 vmu->exit,
11671 vmu->saydurationm,
11672 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11673 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11674 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11675 vmu->attachfmt,
11676 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11677 vmu->volgain,
11678 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11679 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11680 vmu->maxmsg,
11681 vmu->maxsecs,
11682 #ifdef IMAP_STORAGE
11683 new, old, vmu->imapuser
11684 #else
11685 count_messages(vmu, dirname)
11686 #endif
11687 );
11688 }
11689 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11690
11691 AST_LIST_UNLOCK(&users);
11692
11693 return RESULT_SUCCESS;
11694 }
11695
11696
11697 static void free_vm_users(void)
11698 {
11699 struct ast_vm_user *current;
11700 AST_LIST_LOCK(&users);
11701 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11702 ast_set_flag(current, VM_ALLOCED);
11703 free_user(current);
11704 }
11705 AST_LIST_UNLOCK(&users);
11706 }
11707
11708
11709 static void free_vm_zones(void)
11710 {
11711 struct vm_zone *zcur;
11712 AST_LIST_LOCK(&zones);
11713 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11714 free_zone(zcur);
11715 AST_LIST_UNLOCK(&zones);
11716 }
11717
11718 static const char *substitute_escapes(const char *value)
11719 {
11720 char *current;
11721
11722
11723 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11724
11725 ast_str_reset(str);
11726
11727
11728 for (current = (char *) value; *current; current++) {
11729 if (*current == '\\') {
11730 current++;
11731 if (!*current) {
11732 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11733 break;
11734 }
11735 switch (*current) {
11736 case '\\':
11737 ast_str_append(&str, 0, "\\");
11738 break;
11739 case 'r':
11740 ast_str_append(&str, 0, "\r");
11741 break;
11742 case 'n':
11743 #ifdef IMAP_STORAGE
11744 if (!str->used || str->str[str->used - 1] != '\r') {
11745 ast_str_append(&str, 0, "\r");
11746 }
11747 #endif
11748 ast_str_append(&str, 0, "\n");
11749 break;
11750 case 't':
11751 ast_str_append(&str, 0, "\t");
11752 break;
11753 default:
11754 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11755 break;
11756 }
11757 } else {
11758 ast_str_append(&str, 0, "%c", *current);
11759 }
11760 }
11761
11762 return ast_str_buffer(str);
11763 }
11764
11765 static int load_config(int reload)
11766 {
11767 struct ast_config *cfg, *ucfg;
11768 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11769 int res;
11770
11771 ast_unload_realtime("voicemail");
11772 ast_unload_realtime("voicemail_data");
11773
11774 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11775 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11776 return 0;
11777 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11778 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11779 ucfg = NULL;
11780 }
11781 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11782 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11783 ast_config_destroy(ucfg);
11784 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11785 return 0;
11786 }
11787 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11788 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11789 return 0;
11790 } else {
11791 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11792 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11793 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11794 ucfg = NULL;
11795 }
11796 }
11797
11798 res = actual_load_config(reload, cfg, ucfg);
11799
11800 ast_config_destroy(cfg);
11801 ast_config_destroy(ucfg);
11802
11803 return res;
11804 }
11805
11806 #ifdef TEST_FRAMEWORK
11807 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11808 {
11809 ast_unload_realtime("voicemail");
11810 ast_unload_realtime("voicemail_data");
11811 return actual_load_config(reload, cfg, ucfg);
11812 }
11813 #endif
11814
11815 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11816 {
11817 struct ast_vm_user *current;
11818 char *cat;
11819 struct ast_variable *var;
11820 const char *val;
11821 char *q, *stringp, *tmp;
11822 int x;
11823 int tmpadsi[4];
11824 char secretfn[PATH_MAX] = "";
11825
11826 #ifdef IMAP_STORAGE
11827 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11828 #endif
11829
11830 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11831 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11832 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11833 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11834 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11835
11836
11837 free_vm_users();
11838
11839
11840 free_vm_zones();
11841
11842 AST_LIST_LOCK(&users);
11843
11844 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11845 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11846
11847 if (cfg) {
11848
11849
11850 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11851 val = "default";
11852 ast_copy_string(userscontext, val, sizeof(userscontext));
11853
11854 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11855 val = "yes";
11856 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11857
11858 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11859 val = "no";
11860 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11861
11862 volgain = 0.0;
11863 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11864 sscanf(val, "%30lf", &volgain);
11865
11866 #ifdef ODBC_STORAGE
11867 strcpy(odbc_database, "asterisk");
11868 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11869 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11870 }
11871 strcpy(odbc_table, "voicemessages");
11872 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11873 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11874 }
11875 #endif
11876
11877 strcpy(mailcmd, SENDMAIL);
11878 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11879 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11880
11881 maxsilence = 0;
11882 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11883 maxsilence = atoi(val);
11884 if (maxsilence > 0)
11885 maxsilence *= 1000;
11886 }
11887
11888 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11889 maxmsg = MAXMSG;
11890 } else {
11891 maxmsg = atoi(val);
11892 if (maxmsg < 0) {
11893 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11894 maxmsg = MAXMSG;
11895 } else if (maxmsg > MAXMSGLIMIT) {
11896 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11897 maxmsg = MAXMSGLIMIT;
11898 }
11899 }
11900
11901 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11902 maxdeletedmsg = 0;
11903 } else {
11904 if (sscanf(val, "%30d", &x) == 1)
11905 maxdeletedmsg = x;
11906 else if (ast_true(val))
11907 maxdeletedmsg = MAXMSG;
11908 else
11909 maxdeletedmsg = 0;
11910
11911 if (maxdeletedmsg < 0) {
11912 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11913 maxdeletedmsg = MAXMSG;
11914 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11915 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11916 maxdeletedmsg = MAXMSGLIMIT;
11917 }
11918 }
11919
11920
11921 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11922 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11923 }
11924
11925
11926 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11927 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11928 }
11929
11930
11931 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11932 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11933 pwdchange = PWDCHANGE_EXTERNAL;
11934 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11935 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11936 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11937 }
11938
11939
11940 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11941 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11942 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11943 }
11944
11945 #ifdef IMAP_STORAGE
11946
11947 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11948 ast_copy_string(imapserver, val, sizeof(imapserver));
11949 } else {
11950 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11951 }
11952
11953 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11954 ast_copy_string(imapport, val, sizeof(imapport));
11955 } else {
11956 ast_copy_string(imapport, "143", sizeof(imapport));
11957 }
11958
11959 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11960 ast_copy_string(imapflags, val, sizeof(imapflags));
11961 }
11962
11963 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11964 ast_copy_string(authuser, val, sizeof(authuser));
11965 }
11966
11967 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11968 ast_copy_string(authpassword, val, sizeof(authpassword));
11969 }
11970
11971 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11972 if (ast_false(val))
11973 expungeonhangup = 0;
11974 else
11975 expungeonhangup = 1;
11976 } else {
11977 expungeonhangup = 1;
11978 }
11979
11980 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
11981 ast_copy_string(imapfolder, val, sizeof(imapfolder));
11982 } else {
11983 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
11984 }
11985 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
11986 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
11987 }
11988 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
11989 imapgreetings = ast_true(val);
11990 } else {
11991 imapgreetings = 0;
11992 }
11993 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
11994 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11995 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
11996
11997 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11998 } else {
11999 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12000 }
12001
12002
12003
12004
12005
12006 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12007 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12008 } else {
12009 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12010 }
12011
12012 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12013 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12014 } else {
12015 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12016 }
12017
12018 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12019 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12020 } else {
12021 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12022 }
12023
12024 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12025 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12026 } else {
12027 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12028 }
12029
12030
12031 imapversion++;
12032 #endif
12033
12034 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12035 ast_copy_string(externnotify, val, sizeof(externnotify));
12036 ast_debug(1, "found externnotify: %s\n", externnotify);
12037 } else {
12038 externnotify[0] = '\0';
12039 }
12040
12041
12042 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12043 ast_debug(1, "Enabled SMDI voicemail notification\n");
12044 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12045 smdi_iface = ast_smdi_interface_find(val);
12046 } else {
12047 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12048 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12049 }
12050 if (!smdi_iface) {
12051 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12052 }
12053 }
12054
12055
12056 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12057 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12058 silencethreshold = atoi(val);
12059
12060 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12061 val = ASTERISK_USERNAME;
12062 ast_copy_string(serveremail, val, sizeof(serveremail));
12063
12064 vmmaxsecs = 0;
12065 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12066 if (sscanf(val, "%30d", &x) == 1) {
12067 vmmaxsecs = x;
12068 } else {
12069 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12070 }
12071 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12072 static int maxmessage_deprecate = 0;
12073 if (maxmessage_deprecate == 0) {
12074 maxmessage_deprecate = 1;
12075 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12076 }
12077 if (sscanf(val, "%30d", &x) == 1) {
12078 vmmaxsecs = x;
12079 } else {
12080 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12081 }
12082 }
12083
12084 vmminsecs = 0;
12085 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12086 if (sscanf(val, "%30d", &x) == 1) {
12087 vmminsecs = x;
12088 if (maxsilence / 1000 >= vmminsecs) {
12089 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12090 }
12091 } else {
12092 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12093 }
12094 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12095 static int maxmessage_deprecate = 0;
12096 if (maxmessage_deprecate == 0) {
12097 maxmessage_deprecate = 1;
12098 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12099 }
12100 if (sscanf(val, "%30d", &x) == 1) {
12101 vmminsecs = x;
12102 if (maxsilence / 1000 >= vmminsecs) {
12103 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12104 }
12105 } else {
12106 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12107 }
12108 }
12109
12110 val = ast_variable_retrieve(cfg, "general", "format");
12111 if (!val) {
12112 val = "wav";
12113 } else {
12114 tmp = ast_strdupa(val);
12115 val = ast_format_str_reduce(tmp);
12116 if (!val) {
12117 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12118 val = "wav";
12119 }
12120 }
12121 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12122
12123 skipms = 3000;
12124 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12125 if (sscanf(val, "%30d", &x) == 1) {
12126 maxgreet = x;
12127 } else {
12128 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12129 }
12130 }
12131
12132 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12133 if (sscanf(val, "%30d", &x) == 1) {
12134 skipms = x;
12135 } else {
12136 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12137 }
12138 }
12139
12140 maxlogins = 3;
12141 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12142 if (sscanf(val, "%30d", &x) == 1) {
12143 maxlogins = x;
12144 } else {
12145 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12146 }
12147 }
12148
12149 minpassword = MINPASSWORD;
12150 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12151 if (sscanf(val, "%30d", &x) == 1) {
12152 minpassword = x;
12153 } else {
12154 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12155 }
12156 }
12157
12158
12159 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12160 val = "no";
12161 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12162
12163
12164 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12165 val = "no";
12166 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12167
12168 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12169 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12170 stringp = ast_strdupa(val);
12171 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12172 if (!ast_strlen_zero(stringp)) {
12173 q = strsep(&stringp, ",");
12174 while ((*q == ' ')||(*q == '\t'))
12175 q++;
12176 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12177 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12178 } else {
12179 cidinternalcontexts[x][0] = '\0';
12180 }
12181 }
12182 }
12183 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12184 ast_debug(1, "VM Review Option disabled globally\n");
12185 val = "no";
12186 }
12187 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12188
12189
12190 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12191 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12192 val = "no";
12193 } else {
12194 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12195 }
12196 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12197 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12198 ast_debug(1, "VM next message wrap disabled globally\n");
12199 val = "no";
12200 }
12201 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12202
12203 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12204 ast_debug(1, "VM Operator break disabled globally\n");
12205 val = "no";
12206 }
12207 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12208
12209 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12210 ast_debug(1, "VM CID Info before msg disabled globally\n");
12211 val = "no";
12212 }
12213 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12214
12215 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12216 ast_debug(1, "Send Voicemail msg disabled globally\n");
12217 val = "no";
12218 }
12219 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12220
12221 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12222 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12223 val = "yes";
12224 }
12225 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12226
12227 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12228 ast_debug(1, "Move Heard enabled globally\n");
12229 val = "yes";
12230 }
12231 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12232
12233 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12234 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12235 val = "no";
12236 }
12237 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12238
12239 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12240 ast_debug(1, "Duration info before msg enabled globally\n");
12241 val = "yes";
12242 }
12243 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12244
12245 saydurationminfo = 2;
12246 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12247 if (sscanf(val, "%30d", &x) == 1) {
12248 saydurationminfo = x;
12249 } else {
12250 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12251 }
12252 }
12253
12254 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12255 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12256 val = "no";
12257 }
12258 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12259
12260 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12261 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12262 ast_debug(1, "found dialout context: %s\n", dialcontext);
12263 } else {
12264 dialcontext[0] = '\0';
12265 }
12266
12267 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12268 ast_copy_string(callcontext, val, sizeof(callcontext));
12269 ast_debug(1, "found callback context: %s\n", callcontext);
12270 } else {
12271 callcontext[0] = '\0';
12272 }
12273
12274 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12275 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12276 ast_debug(1, "found operator context: %s\n", exitcontext);
12277 } else {
12278 exitcontext[0] = '\0';
12279 }
12280
12281
12282 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12283 ast_copy_string(vm_password, val, sizeof(vm_password));
12284 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12285 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12286 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12287 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12288 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12289 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12290 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12291 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12292 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12293 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12294 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12295 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12296 }
12297 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12298 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12299 }
12300
12301 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12302 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12303 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12304 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12305 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12306 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12307 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12308 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12309 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12310 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12311
12312 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12313 val = "no";
12314 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12315
12316 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12317 val = "voicemail.conf";
12318 }
12319 if (!(strcmp(val, "spooldir"))) {
12320 passwordlocation = OPT_PWLOC_SPOOLDIR;
12321 } else {
12322 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12323 }
12324
12325 poll_freq = DEFAULT_POLL_FREQ;
12326 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12327 if (sscanf(val, "%30u", &poll_freq) != 1) {
12328 poll_freq = DEFAULT_POLL_FREQ;
12329 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12330 }
12331 }
12332
12333 poll_mailboxes = 0;
12334 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12335 poll_mailboxes = ast_true(val);
12336
12337 memset(fromstring, 0, sizeof(fromstring));
12338 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12339 strcpy(charset, "ISO-8859-1");
12340 if (emailbody) {
12341 ast_free(emailbody);
12342 emailbody = NULL;
12343 }
12344 if (emailsubject) {
12345 ast_free(emailsubject);
12346 emailsubject = NULL;
12347 }
12348 if (pagerbody) {
12349 ast_free(pagerbody);
12350 pagerbody = NULL;
12351 }
12352 if (pagersubject) {
12353 ast_free(pagersubject);
12354 pagersubject = NULL;
12355 }
12356 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12357 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12358 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12359 ast_copy_string(fromstring, val, sizeof(fromstring));
12360 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12361 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12362 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12363 ast_copy_string(charset, val, sizeof(charset));
12364 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12365 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12366 for (x = 0; x < 4; x++) {
12367 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12368 }
12369 }
12370 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12371 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12372 for (x = 0; x < 4; x++) {
12373 memcpy(&adsisec[x], &tmpadsi[x], 1);
12374 }
12375 }
12376 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12377 if (atoi(val)) {
12378 adsiver = atoi(val);
12379 }
12380 }
12381 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12382 ast_copy_string(zonetag, val, sizeof(zonetag));
12383 }
12384 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12385 ast_copy_string(locale, val, sizeof(locale));
12386 }
12387 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12388 emailsubject = ast_strdup(substitute_escapes(val));
12389 }
12390 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12391 emailbody = ast_strdup(substitute_escapes(val));
12392 }
12393 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12394 pagersubject = ast_strdup(substitute_escapes(val));
12395 }
12396 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12397 pagerbody = ast_strdup(substitute_escapes(val));
12398 }
12399
12400
12401 if (ucfg) {
12402 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12403 if (!strcasecmp(cat, "general")) {
12404 continue;
12405 }
12406 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12407 continue;
12408 if ((current = find_or_create(userscontext, cat))) {
12409 populate_defaults(current);
12410 apply_options_full(current, ast_variable_browse(ucfg, cat));
12411 ast_copy_string(current->context, userscontext, sizeof(current->context));
12412 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12413 current->passwordlocation = OPT_PWLOC_USERSCONF;
12414 }
12415
12416 switch (current->passwordlocation) {
12417 case OPT_PWLOC_SPOOLDIR:
12418 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12419 read_password_from_file(secretfn, current->password, sizeof(current->password));
12420 }
12421 }
12422 }
12423 }
12424
12425
12426 cat = ast_category_browse(cfg, NULL);
12427 while (cat) {
12428 if (strcasecmp(cat, "general")) {
12429 var = ast_variable_browse(cfg, cat);
12430 if (strcasecmp(cat, "zonemessages")) {
12431
12432 while (var) {
12433 append_mailbox(cat, var->name, var->value);
12434 var = var->next;
12435 }
12436 } else {
12437
12438 while (var) {
12439 struct vm_zone *z;
12440 if ((z = ast_malloc(sizeof(*z)))) {
12441 char *msg_format, *tzone;
12442 msg_format = ast_strdupa(var->value);
12443 tzone = strsep(&msg_format, "|,");
12444 if (msg_format) {
12445 ast_copy_string(z->name, var->name, sizeof(z->name));
12446 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12447 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12448 AST_LIST_LOCK(&zones);
12449 AST_LIST_INSERT_HEAD(&zones, z, list);
12450 AST_LIST_UNLOCK(&zones);
12451 } else {
12452 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12453 ast_free(z);
12454 }
12455 } else {
12456 AST_LIST_UNLOCK(&users);
12457 return -1;
12458 }
12459 var = var->next;
12460 }
12461 }
12462 }
12463 cat = ast_category_browse(cfg, cat);
12464 }
12465
12466 AST_LIST_UNLOCK(&users);
12467
12468 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12469 start_poll_thread();
12470 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12471 stop_poll_thread();;
12472
12473 return 0;
12474 } else {
12475 AST_LIST_UNLOCK(&users);
12476 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12477 return 0;
12478 }
12479 }
12480
12481 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12482 {
12483 int res = -1;
12484 char dir[PATH_MAX];
12485 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12486 ast_debug(2, "About to try retrieving name file %s\n", dir);
12487 RETRIEVE(dir, -1, mailbox, context);
12488 if (ast_fileexists(dir, NULL, NULL)) {
12489 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12490 }
12491 DISPOSE(dir, -1);
12492 return res;
12493 }
12494
12495 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12496 struct ast_config *pwconf;
12497 struct ast_flags config_flags = { 0 };
12498
12499 pwconf = ast_config_load(secretfn, config_flags);
12500 if (pwconf) {
12501 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12502 if (val) {
12503 ast_copy_string(password, val, passwordlen);
12504 return;
12505 }
12506 }
12507 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12508 }
12509
12510 static int write_password_to_file(const char *secretfn, const char *password) {
12511 struct ast_config *conf;
12512 struct ast_category *cat;
12513 struct ast_variable *var;
12514
12515 if (!(conf=ast_config_new())) {
12516 ast_log(LOG_ERROR, "Error creating new config structure\n");
12517 return -1;
12518 }
12519 if (!(cat=ast_category_new("general","",1))) {
12520 ast_log(LOG_ERROR, "Error creating new category structure\n");
12521 return -1;
12522 }
12523 if (!(var=ast_variable_new("password",password,""))) {
12524 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12525 return -1;
12526 }
12527 ast_category_append(conf,cat);
12528 ast_variable_append(cat,var);
12529 if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12530 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12531 return -1;
12532 }
12533 return 0;
12534 }
12535
12536 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12537 {
12538 char *context;
12539 char *args_copy;
12540 int res;
12541
12542 if (ast_strlen_zero(data)) {
12543 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context");
12544 return -1;
12545 }
12546
12547 args_copy = ast_strdupa(data);
12548 if ((context = strchr(args_copy, '@'))) {
12549 *context++ = '\0';
12550 } else {
12551 context = "default";
12552 }
12553
12554 if ((res = sayname(chan, args_copy, context) < 0)) {
12555 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12556 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12557 if (!res) {
12558 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12559 }
12560 }
12561
12562 return res;
12563 }
12564
12565 #ifdef TEST_FRAMEWORK
12566 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12567 {
12568 return 0;
12569 }
12570
12571 static struct ast_frame *fake_read(struct ast_channel *ast)
12572 {
12573 return &ast_null_frame;
12574 }
12575
12576 AST_TEST_DEFINE(test_voicemail_vmsayname)
12577 {
12578 char dir[PATH_MAX];
12579 char dir2[PATH_MAX];
12580 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12581 static const char TEST_EXTENSION[] = "1234";
12582
12583 struct ast_channel *test_channel1 = NULL;
12584 int res = -1;
12585
12586 static const struct ast_channel_tech fake_tech = {
12587 .write = fake_write,
12588 .read = fake_read,
12589 };
12590
12591 switch (cmd) {
12592 case TEST_INIT:
12593 info->name = "vmsayname_exec";
12594 info->category = "/apps/app_voicemail/";
12595 info->summary = "Vmsayname unit test";
12596 info->description =
12597 "This tests passing various parameters to vmsayname";
12598 return AST_TEST_NOT_RUN;
12599 case TEST_EXECUTE:
12600 break;
12601 }
12602
12603 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12604 NULL, NULL, 0, 0, "TestChannel1"))) {
12605 goto exit_vmsayname_test;
12606 }
12607
12608
12609 test_channel1->nativeformats = AST_FORMAT_GSM;
12610 test_channel1->writeformat = AST_FORMAT_GSM;
12611 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12612 test_channel1->readformat = AST_FORMAT_GSM;
12613 test_channel1->rawreadformat = AST_FORMAT_GSM;
12614 test_channel1->tech = &fake_tech;
12615
12616 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12617 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12618 if (!(res = vmsayname_exec(test_channel1, dir))) {
12619 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12620 if (ast_fileexists(dir, NULL, NULL)) {
12621 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12622 res = -1;
12623 goto exit_vmsayname_test;
12624 } else {
12625
12626 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12627 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12628 goto exit_vmsayname_test;
12629 }
12630 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12631 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12632
12633 if ((res = symlink(dir, dir2))) {
12634 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12635 goto exit_vmsayname_test;
12636 }
12637 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12638 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12639 res = vmsayname_exec(test_channel1, dir);
12640
12641
12642 unlink(dir2);
12643 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12644 rmdir(dir2);
12645 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12646 rmdir(dir2);
12647 }
12648 }
12649
12650 exit_vmsayname_test:
12651
12652 if (test_channel1) {
12653 ast_hangup(test_channel1);
12654 }
12655
12656 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12657 }
12658
12659 AST_TEST_DEFINE(test_voicemail_msgcount)
12660 {
12661 int i, j, res = AST_TEST_PASS, syserr;
12662 struct ast_vm_user *vmu;
12663 struct vm_state vms;
12664 #ifdef IMAP_STORAGE
12665 struct ast_channel *chan = NULL;
12666 #endif
12667 struct {
12668 char dir[256];
12669 char file[256];
12670 char txtfile[256];
12671 } tmp[3];
12672 char syscmd[256];
12673 const char origweasels[] = "tt-weasels";
12674 const char testcontext[] = "test";
12675 const char testmailbox[] = "00000000";
12676 const char testspec[] = "00000000@test";
12677 FILE *txt;
12678 int new, old, urgent;
12679 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12680 const int folder2mbox[3] = { 1, 11, 0 };
12681 const int expected_results[3][12] = {
12682
12683 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12684 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12685 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12686 };
12687
12688 switch (cmd) {
12689 case TEST_INIT:
12690 info->name = "test_voicemail_msgcount";
12691 info->category = "/apps/app_voicemail/";
12692 info->summary = "Test Voicemail status checks";
12693 info->description =
12694 "Verify that message counts are correct when retrieved through the public API";
12695 return AST_TEST_NOT_RUN;
12696 case TEST_EXECUTE:
12697 break;
12698 }
12699
12700
12701 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12702 if ((syserr = ast_safe_system(syscmd))) {
12703 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12704 syserr > 0 ? strerror(syserr) : "unable to fork()");
12705 return AST_TEST_FAIL;
12706 }
12707
12708 #ifdef IMAP_STORAGE
12709 if (!(chan = ast_dummy_channel_alloc())) {
12710 ast_test_status_update(test, "Unable to create dummy channel\n");
12711 return AST_TEST_FAIL;
12712 }
12713 #endif
12714
12715 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12716 !(vmu = find_or_create(testcontext, testmailbox))) {
12717 ast_test_status_update(test, "Cannot create vmu structure\n");
12718 ast_unreplace_sigchld();
12719 #ifdef IMAP_STORAGE
12720 chan = ast_channel_unref(chan);
12721 #endif
12722 return AST_TEST_FAIL;
12723 }
12724
12725 populate_defaults(vmu);
12726 memset(&vms, 0, sizeof(vms));
12727
12728
12729 for (i = 0; i < 3; i++) {
12730 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12731 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12732 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12733
12734 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12735 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12736 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12737 if ((syserr = ast_safe_system(syscmd))) {
12738 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12739 syserr > 0 ? strerror(syserr) : "unable to fork()");
12740 ast_unreplace_sigchld();
12741 #ifdef IMAP_STORAGE
12742 chan = ast_channel_unref(chan);
12743 #endif
12744 return AST_TEST_FAIL;
12745 }
12746 }
12747
12748 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12749 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12750 fclose(txt);
12751 } else {
12752 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12753 res = AST_TEST_FAIL;
12754 break;
12755 }
12756 open_mailbox(&vms, vmu, folder2mbox[i]);
12757 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12758
12759
12760 for (j = 0; j < 3; j++) {
12761
12762 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12763 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12764 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12765 res = AST_TEST_FAIL;
12766 }
12767 }
12768
12769 new = old = urgent = 0;
12770 if (ast_app_inboxcount(testspec, &new, &old)) {
12771 ast_test_status_update(test, "inboxcount returned failure\n");
12772 res = AST_TEST_FAIL;
12773 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12774 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12775 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12776 res = AST_TEST_FAIL;
12777 }
12778
12779 new = old = urgent = 0;
12780 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12781 ast_test_status_update(test, "inboxcount2 returned failure\n");
12782 res = AST_TEST_FAIL;
12783 } else if (old != expected_results[i][6 + 0] ||
12784 urgent != expected_results[i][6 + 1] ||
12785 new != expected_results[i][6 + 2] ) {
12786 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12787 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12788 res = AST_TEST_FAIL;
12789 }
12790
12791 new = old = urgent = 0;
12792 for (j = 0; j < 3; j++) {
12793 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12794 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12795 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12796 res = AST_TEST_FAIL;
12797 }
12798 }
12799 }
12800
12801 for (i = 0; i < 3; i++) {
12802
12803
12804
12805 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12806 DISPOSE(tmp[i].dir, 0);
12807 }
12808
12809 if (vms.deleted) {
12810 ast_free(vms.deleted);
12811 }
12812 if (vms.heard) {
12813 ast_free(vms.heard);
12814 }
12815
12816 #ifdef IMAP_STORAGE
12817 chan = ast_channel_unref(chan);
12818 #endif
12819
12820
12821 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12822 if ((syserr = ast_safe_system(syscmd))) {
12823 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12824 syserr > 0 ? strerror(syserr) : "unable to fork()");
12825 }
12826
12827 return res;
12828 }
12829
12830 AST_TEST_DEFINE(test_voicemail_notify_endl)
12831 {
12832 int res = AST_TEST_PASS;
12833 char testcontext[] = "test";
12834 char testmailbox[] = "00000000";
12835 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12836 char attach[256], attach2[256];
12837 char buf[256] = "";
12838 struct ast_channel *chan = NULL;
12839 struct ast_vm_user *vmu, vmus = {
12840 .flags = 0,
12841 };
12842 FILE *file;
12843 struct {
12844 char *name;
12845 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12846 void *location;
12847 union {
12848 int intval;
12849 char *strval;
12850 } u;
12851 } test_items[] = {
12852 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12853 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12854 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12855 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12856 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12857 { "attach2", STRPTR, attach2, .u.strval = "" },
12858 { "attach", STRPTR, attach, .u.strval = "" },
12859 };
12860 int which;
12861
12862 switch (cmd) {
12863 case TEST_INIT:
12864 info->name = "test_voicemail_notify_endl";
12865 info->category = "/apps/app_voicemail/";
12866 info->summary = "Test Voicemail notification end-of-line";
12867 info->description =
12868 "Verify that notification emails use a consistent end-of-line character";
12869 return AST_TEST_NOT_RUN;
12870 case TEST_EXECUTE:
12871 break;
12872 }
12873
12874 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12875 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12876
12877 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12878 !(vmu = find_or_create(testcontext, testmailbox))) {
12879 ast_test_status_update(test, "Cannot create vmu structure\n");
12880 return AST_TEST_NOT_RUN;
12881 }
12882
12883 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12884 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12885 return AST_TEST_NOT_RUN;
12886 }
12887
12888 populate_defaults(vmu);
12889 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12890 #ifdef IMAP_STORAGE
12891
12892 #endif
12893
12894 file = tmpfile();
12895 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12896
12897 rewind(file);
12898 if (ftruncate(fileno(file), 0)) {
12899 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12900 res = AST_TEST_FAIL;
12901 break;
12902 }
12903
12904
12905 if (test_items[which].type == INT) {
12906 *((int *) test_items[which].location) = test_items[which].u.intval;
12907 } else if (test_items[which].type == FLAGVAL) {
12908 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12909 ast_clear_flag(vmu, test_items[which].u.intval);
12910 } else {
12911 ast_set_flag(vmu, test_items[which].u.intval);
12912 }
12913 } else if (test_items[which].type == STATIC) {
12914 strcpy(test_items[which].location, test_items[which].u.strval);
12915 } else if (test_items[which].type == STRPTR) {
12916 test_items[which].location = test_items[which].u.strval;
12917 }
12918
12919 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12920 rewind(file);
12921 while (fgets(buf, sizeof(buf), file)) {
12922 if (
12923 #ifdef IMAP_STORAGE
12924 buf[strlen(buf) - 2] != '\r'
12925 #else
12926 buf[strlen(buf) - 2] == '\r'
12927 #endif
12928 || buf[strlen(buf) - 1] != '\n') {
12929 res = AST_TEST_FAIL;
12930 }
12931 }
12932 }
12933 fclose(file);
12934 return res;
12935 }
12936
12937 AST_TEST_DEFINE(test_voicemail_load_config)
12938 {
12939 int res = AST_TEST_PASS;
12940 struct ast_vm_user *vmu;
12941 struct ast_config *cfg;
12942 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
12943 int fd;
12944 FILE *file;
12945 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
12946
12947 switch (cmd) {
12948 case TEST_INIT:
12949 info->name = "test_voicemail_load_config";
12950 info->category = "/apps/app_voicemail/";
12951 info->summary = "Test loading Voicemail config";
12952 info->description =
12953 "Verify that configuration is loaded consistently. "
12954 "This is to test regressions of ASTERISK-18838 where it was noticed that "
12955 "some options were loaded after the mailboxes were instantiated, causing "
12956 "those options not to be set correctly.";
12957 return AST_TEST_NOT_RUN;
12958 case TEST_EXECUTE:
12959 break;
12960 }
12961
12962
12963 if ((fd = mkstemp(config_filename)) < 0) {
12964 return AST_TEST_FAIL;
12965 }
12966 if (!(file = fdopen(fd, "w"))) {
12967 close(fd);
12968 unlink(config_filename);
12969 return AST_TEST_FAIL;
12970 }
12971 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
12972 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
12973 fputs("00000002 => 9999,Mrs. Test\n", file);
12974 fclose(file);
12975
12976 if (!(cfg = ast_config_load(config_filename, config_flags))) {
12977 res = AST_TEST_FAIL;
12978 goto cleanup;
12979 }
12980
12981 load_config_from_memory(1, cfg, NULL);
12982 ast_config_destroy(cfg);
12983
12984 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
12985 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
12986 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
12987
12988 AST_LIST_LOCK(&users);
12989 AST_LIST_TRAVERSE(&users, vmu, list) {
12990 if (!strcmp(vmu->mailbox, "00000001")) {
12991 if (0);
12992 CHECK(vmu, callback, "othercontext")
12993 CHECK(vmu, locale, "nl_NL.UTF-8")
12994 CHECK(vmu, zonetag, "central")
12995 } else if (!strcmp(vmu->mailbox, "00000002")) {
12996 if (0);
12997 CHECK(vmu, callback, "somecontext")
12998 CHECK(vmu, locale, "de_DE.UTF-8")
12999 CHECK(vmu, zonetag, "european")
13000 }
13001 }
13002 AST_LIST_UNLOCK(&users);
13003
13004 #undef CHECK
13005
13006
13007 load_config(1);
13008
13009 cleanup:
13010 unlink(config_filename);
13011 return res;
13012 }
13013
13014 #endif
13015
13016 static int reload(void)
13017 {
13018 return load_config(1);
13019 }
13020
13021 static int unload_module(void)
13022 {
13023 int res;
13024
13025 res = ast_unregister_application(app);
13026 res |= ast_unregister_application(app2);
13027 res |= ast_unregister_application(app3);
13028 res |= ast_unregister_application(app4);
13029 res |= ast_unregister_application(sayname_app);
13030 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13031 res |= ast_manager_unregister("VoicemailUsersList");
13032 res |= ast_data_unregister(NULL);
13033 #ifdef TEST_FRAMEWORK
13034 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13035 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13036 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13037 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13038 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13039 #endif
13040 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13041 ast_uninstall_vm_functions();
13042 ao2_ref(inprocess_container, -1);
13043
13044 if (poll_thread != AST_PTHREADT_NULL)
13045 stop_poll_thread();
13046
13047 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13048 ast_unload_realtime("voicemail");
13049 ast_unload_realtime("voicemail_data");
13050
13051 free_vm_users();
13052 free_vm_zones();
13053 return res;
13054 }
13055
13056 static int load_module(void)
13057 {
13058 int res;
13059 my_umask = umask(0);
13060 umask(my_umask);
13061
13062 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13063 return AST_MODULE_LOAD_DECLINE;
13064 }
13065
13066
13067 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13068
13069 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13070 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13071 }
13072
13073 if ((res = load_config(0)))
13074 return res;
13075
13076 res = ast_register_application_xml(app, vm_exec);
13077 res |= ast_register_application_xml(app2, vm_execmain);
13078 res |= ast_register_application_xml(app3, vm_box_exists);
13079 res |= ast_register_application_xml(app4, vmauthenticate);
13080 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13081 res |= ast_custom_function_register(&mailbox_exists_acf);
13082 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13083 #ifdef TEST_FRAMEWORK
13084 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13085 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13086 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13087 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13088 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13089 #endif
13090
13091 if (res)
13092 return res;
13093
13094 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13095 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13096
13097 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13098 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13099 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13100
13101 return res;
13102 }
13103
13104 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13105 {
13106 int cmd = 0;
13107 char destination[80] = "";
13108 int retries = 0;
13109
13110 if (!num) {
13111 ast_verb(3, "Destination number will be entered manually\n");
13112 while (retries < 3 && cmd != 't') {
13113 destination[1] = '\0';
13114 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13115 if (!cmd)
13116 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13117 if (!cmd)
13118 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13119 if (!cmd) {
13120 cmd = ast_waitfordigit(chan, 6000);
13121 if (cmd)
13122 destination[0] = cmd;
13123 }
13124 if (!cmd) {
13125 retries++;
13126 } else {
13127
13128 if (cmd < 0)
13129 return 0;
13130 if (cmd == '*') {
13131 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13132 return 0;
13133 }
13134 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13135 retries++;
13136 else
13137 cmd = 't';
13138 }
13139 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13140 }
13141 if (retries >= 3) {
13142 return 0;
13143 }
13144
13145 } else {
13146 if (option_verbose > 2)
13147 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13148 ast_copy_string(destination, num, sizeof(destination));
13149 }
13150
13151 if (!ast_strlen_zero(destination)) {
13152 if (destination[strlen(destination) -1 ] == '*')
13153 return 0;
13154 if (option_verbose > 2)
13155 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13156 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13157 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13158 chan->priority = 0;
13159 return 9;
13160 }
13161 return 0;
13162 }
13163
13164
13165
13166
13167
13168
13169
13170
13171
13172
13173
13174
13175
13176
13177 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)
13178 {
13179 int res = 0;
13180 char filename[PATH_MAX];
13181 struct ast_config *msg_cfg = NULL;
13182 const char *origtime, *context;
13183 char *name, *num;
13184 int retries = 0;
13185 char *cid;
13186 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13187
13188 vms->starting = 0;
13189
13190 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13191
13192
13193 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13194 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13195 msg_cfg = ast_config_load(filename, config_flags);
13196 DISPOSE(vms->curdir, vms->curmsg);
13197 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13198 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13199 return 0;
13200 }
13201
13202 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13203 ast_config_destroy(msg_cfg);
13204 return 0;
13205 }
13206
13207 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13208
13209 context = ast_variable_retrieve(msg_cfg, "message", "context");
13210 if (!strncasecmp("macro", context, 5))
13211 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13212 switch (option) {
13213 case 3:
13214 if (!res)
13215 res = play_message_datetime(chan, vmu, origtime, filename);
13216 if (!res)
13217 res = play_message_callerid(chan, vms, cid, context, 0);
13218
13219 res = 't';
13220 break;
13221
13222 case 2:
13223
13224 if (ast_strlen_zero(cid))
13225 break;
13226
13227 ast_callerid_parse(cid, &name, &num);
13228 while ((res > -1) && (res != 't')) {
13229 switch (res) {
13230 case '1':
13231 if (num) {
13232
13233 res = dialout(chan, vmu, num, vmu->callback);
13234 if (res) {
13235 ast_config_destroy(msg_cfg);
13236 return 9;
13237 }
13238 } else {
13239 res = '2';
13240 }
13241 break;
13242
13243 case '2':
13244
13245 if (!ast_strlen_zero(vmu->dialout)) {
13246 res = dialout(chan, vmu, NULL, vmu->dialout);
13247 if (res) {
13248 ast_config_destroy(msg_cfg);
13249 return 9;
13250 }
13251 } else {
13252 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13253 res = ast_play_and_wait(chan, "vm-sorry");
13254 }
13255 ast_config_destroy(msg_cfg);
13256 return res;
13257 case '*':
13258 res = 't';
13259 break;
13260 case '3':
13261 case '4':
13262 case '5':
13263 case '6':
13264 case '7':
13265 case '8':
13266 case '9':
13267 case '0':
13268
13269 res = ast_play_and_wait(chan, "vm-sorry");
13270 retries++;
13271 break;
13272 default:
13273 if (num) {
13274 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13275 res = ast_play_and_wait(chan, "vm-num-i-have");
13276 if (!res)
13277 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13278 if (!res)
13279 res = ast_play_and_wait(chan, "vm-tocallnum");
13280
13281 if (!ast_strlen_zero(vmu->dialout)) {
13282 if (!res)
13283 res = ast_play_and_wait(chan, "vm-calldiffnum");
13284 }
13285 } else {
13286 res = ast_play_and_wait(chan, "vm-nonumber");
13287 if (!ast_strlen_zero(vmu->dialout)) {
13288 if (!res)
13289 res = ast_play_and_wait(chan, "vm-toenternumber");
13290 }
13291 }
13292 if (!res) {
13293 res = ast_play_and_wait(chan, "vm-star-cancel");
13294 }
13295 if (!res) {
13296 res = ast_waitfordigit(chan, 6000);
13297 }
13298 if (!res) {
13299 retries++;
13300 if (retries > 3) {
13301 res = 't';
13302 }
13303 }
13304 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13305 break;
13306
13307 }
13308 if (res == 't')
13309 res = 0;
13310 else if (res == '*')
13311 res = -1;
13312 }
13313 break;
13314
13315 case 1:
13316
13317 if (ast_strlen_zero(cid))
13318 break;
13319
13320 ast_callerid_parse(cid, &name, &num);
13321 if (!num) {
13322 ast_verb(3, "No CID number available, no reply sent\n");
13323 if (!res)
13324 res = ast_play_and_wait(chan, "vm-nonumber");
13325 ast_config_destroy(msg_cfg);
13326 return res;
13327 } else {
13328 struct ast_vm_user vmu2;
13329 if (find_user(&vmu2, vmu->context, num)) {
13330 struct leave_vm_options leave_options;
13331 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13332 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13333
13334 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13335
13336 memset(&leave_options, 0, sizeof(leave_options));
13337 leave_options.record_gain = record_gain;
13338 res = leave_voicemail(chan, mailbox, &leave_options);
13339 if (!res)
13340 res = 't';
13341 ast_config_destroy(msg_cfg);
13342 return res;
13343 } else {
13344
13345 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13346 ast_play_and_wait(chan, "vm-nobox");
13347 res = 't';
13348 ast_config_destroy(msg_cfg);
13349 return res;
13350 }
13351 }
13352 res = 0;
13353
13354 break;
13355 }
13356
13357 #ifndef IMAP_STORAGE
13358 ast_config_destroy(msg_cfg);
13359
13360 if (!res) {
13361 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13362 vms->heard[msg] = 1;
13363 res = wait_file(chan, vms, vms->fn);
13364 }
13365 #endif
13366 return res;
13367 }
13368
13369 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13370 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13371 signed char record_gain, struct vm_state *vms, char *flag)
13372 {
13373
13374 int res = 0;
13375 int cmd = 0;
13376 int max_attempts = 3;
13377 int attempts = 0;
13378 int recorded = 0;
13379 int msg_exists = 0;
13380 signed char zero_gain = 0;
13381 char tempfile[PATH_MAX];
13382 char *acceptdtmf = "#";
13383 char *canceldtmf = "";
13384 int canceleddtmf = 0;
13385
13386
13387
13388
13389 if (duration == NULL) {
13390 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13391 return -1;
13392 }
13393
13394 if (!outsidecaller)
13395 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13396 else
13397 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13398
13399 cmd = '3';
13400
13401 while ((cmd >= 0) && (cmd != 't')) {
13402 switch (cmd) {
13403 case '1':
13404 if (!msg_exists) {
13405
13406 cmd = '3';
13407 break;
13408 } else {
13409
13410 ast_verb(3, "Saving message as is\n");
13411 if (!outsidecaller)
13412 ast_filerename(tempfile, recordfile, NULL);
13413 ast_stream_and_wait(chan, "vm-msgsaved", "");
13414 if (!outsidecaller) {
13415
13416 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13417 DISPOSE(recordfile, -1);
13418 }
13419 cmd = 't';
13420 return res;
13421 }
13422 case '2':
13423
13424 ast_verb(3, "Reviewing the message\n");
13425 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13426 break;
13427 case '3':
13428 msg_exists = 0;
13429
13430 if (recorded == 1)
13431 ast_verb(3, "Re-recording the message\n");
13432 else
13433 ast_verb(3, "Recording the message\n");
13434
13435 if (recorded && outsidecaller) {
13436 cmd = ast_play_and_wait(chan, INTRO);
13437 cmd = ast_play_and_wait(chan, "beep");
13438 }
13439 recorded = 1;
13440
13441 if (record_gain)
13442 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13443 if (ast_test_flag(vmu, VM_OPERATOR))
13444 canceldtmf = "0";
13445 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13446 if (strchr(canceldtmf, cmd)) {
13447
13448 canceleddtmf = 1;
13449 }
13450 if (record_gain)
13451 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13452 if (cmd == -1) {
13453
13454 if (!outsidecaller) {
13455
13456 ast_filedelete(tempfile, NULL);
13457 }
13458 return cmd;
13459 }
13460 if (cmd == '0') {
13461 break;
13462 } else if (cmd == '*') {
13463 break;
13464 #if 0
13465 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13466
13467 ast_verb(3, "Message too short\n");
13468 cmd = ast_play_and_wait(chan, "vm-tooshort");
13469 cmd = ast_filedelete(tempfile, NULL);
13470 break;
13471 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13472
13473 ast_verb(3, "Nothing recorded\n");
13474 cmd = ast_filedelete(tempfile, NULL);
13475 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13476 if (!cmd)
13477 cmd = ast_play_and_wait(chan, "vm-speakup");
13478 break;
13479 #endif
13480 } else {
13481
13482 msg_exists = 1;
13483 cmd = 0;
13484 }
13485 break;
13486 case '4':
13487 if (outsidecaller) {
13488
13489 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13490 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13491 res = ast_play_and_wait(chan, "vm-marked-urgent");
13492 strcpy(flag, "Urgent");
13493 } else if (flag) {
13494 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13495 res = ast_play_and_wait(chan, "vm-urgent-removed");
13496 strcpy(flag, "");
13497 } else {
13498 ast_play_and_wait(chan, "vm-sorry");
13499 }
13500 cmd = 0;
13501 } else {
13502 cmd = ast_play_and_wait(chan, "vm-sorry");
13503 }
13504 break;
13505 case '5':
13506 case '6':
13507 case '7':
13508 case '8':
13509 case '9':
13510 case '*':
13511 case '#':
13512 cmd = ast_play_and_wait(chan, "vm-sorry");
13513 break;
13514 #if 0
13515
13516
13517 case '*':
13518
13519 cmd = ast_play_and_wait(chan, "vm-deleted");
13520 cmd = ast_filedelete(tempfile, NULL);
13521 if (outsidecaller) {
13522 res = vm_exec(chan, NULL);
13523 return res;
13524 }
13525 else
13526 return 1;
13527 #endif
13528 case '0':
13529 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13530 cmd = ast_play_and_wait(chan, "vm-sorry");
13531 break;
13532 }
13533 if (msg_exists || recorded) {
13534 cmd = ast_play_and_wait(chan, "vm-saveoper");
13535 if (!cmd)
13536 cmd = ast_waitfordigit(chan, 3000);
13537 if (cmd == '1') {
13538 ast_filerename(tempfile, recordfile, NULL);
13539 ast_play_and_wait(chan, "vm-msgsaved");
13540 cmd = '0';
13541 } else if (cmd == '4') {
13542 if (flag) {
13543 ast_play_and_wait(chan, "vm-marked-urgent");
13544 strcpy(flag, "Urgent");
13545 }
13546 ast_play_and_wait(chan, "vm-msgsaved");
13547 cmd = '0';
13548 } else {
13549 ast_play_and_wait(chan, "vm-deleted");
13550 DELETE(tempfile, -1, tempfile, vmu);
13551 cmd = '0';
13552 }
13553 }
13554 return cmd;
13555 default:
13556
13557
13558
13559 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13560 return cmd;
13561 if (msg_exists) {
13562 cmd = ast_play_and_wait(chan, "vm-review");
13563 if (!cmd && outsidecaller) {
13564 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13565 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13566 } else if (flag) {
13567 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13568 }
13569 }
13570 } else {
13571 cmd = ast_play_and_wait(chan, "vm-torerecord");
13572 if (!cmd)
13573 cmd = ast_waitfordigit(chan, 600);
13574 }
13575
13576 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13577 cmd = ast_play_and_wait(chan, "vm-reachoper");
13578 if (!cmd)
13579 cmd = ast_waitfordigit(chan, 600);
13580 }
13581 #if 0
13582 if (!cmd)
13583 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13584 #endif
13585 if (!cmd)
13586 cmd = ast_waitfordigit(chan, 6000);
13587 if (!cmd) {
13588 attempts++;
13589 }
13590 if (attempts > max_attempts) {
13591 cmd = 't';
13592 }
13593 }
13594 }
13595 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13596
13597 ast_filedelete(tempfile, NULL);
13598 }
13599
13600 if (cmd != 't' && outsidecaller)
13601 ast_play_and_wait(chan, "vm-goodbye");
13602
13603 return cmd;
13604 }
13605
13606
13607
13608
13609
13610 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13611 .load = load_module,
13612 .unload = unload_module,
13613 .reload = reload,
13614 .nonoptreq = "res_adsi,res_smdi",
13615 );