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: 352643 $")
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
07942 #ifndef IMAP_STORAGE
07943 int last_msg_idx;
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 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
08021 if (vms->deleted[x]) {
08022 ast_debug(3, "IMAP delete of %d\n", x);
08023 DELETE(vms->curdir, x, vms->fn, vmu);
08024 }
08025 }
08026 }
08027 #endif
08028
08029 done:
08030 if (vms->deleted && vmu->maxmsg) {
08031 memset(vms->deleted, 0, vms->dh_arraysize * sizeof(int));
08032 }
08033 if (vms->heard && vmu->maxmsg) {
08034 memset(vms->heard, 0, vms->dh_arraysize * sizeof(int));
08035 }
08036
08037 return 0;
08038 }
08039
08040
08041
08042
08043
08044
08045
08046 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08047 {
08048 int cmd;
08049 char *buf;
08050
08051 buf = alloca(strlen(box) + 2);
08052 strcpy(buf, box);
08053 strcat(buf, "s");
08054
08055 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08056 cmd = ast_play_and_wait(chan, buf);
08057 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08058 } else {
08059 cmd = ast_play_and_wait(chan, "vm-messages");
08060 return cmd ? cmd : ast_play_and_wait(chan, box);
08061 }
08062 }
08063
08064 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08065 {
08066 int cmd;
08067
08068 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08069 if (!strcasecmp(box, "vm-INBOX"))
08070 cmd = ast_play_and_wait(chan, "vm-new-e");
08071 else
08072 cmd = ast_play_and_wait(chan, "vm-old-e");
08073 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08074 } else {
08075 cmd = ast_play_and_wait(chan, "vm-messages");
08076 return cmd ? cmd : ast_play_and_wait(chan, box);
08077 }
08078 }
08079
08080 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08081 {
08082 int cmd;
08083
08084 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08085 cmd = ast_play_and_wait(chan, "vm-messages");
08086 return cmd ? cmd : ast_play_and_wait(chan, box);
08087 } else {
08088 cmd = ast_play_and_wait(chan, box);
08089 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08090 }
08091 }
08092
08093 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08094 {
08095 int cmd;
08096
08097 if ( !strncasecmp(chan->language, "it", 2) ||
08098 !strncasecmp(chan->language, "es", 2) ||
08099 !strncasecmp(chan->language, "pt", 2)) {
08100 cmd = ast_play_and_wait(chan, "vm-messages");
08101 return cmd ? cmd : ast_play_and_wait(chan, box);
08102 } else if (!strncasecmp(chan->language, "gr", 2)) {
08103 return vm_play_folder_name_gr(chan, box);
08104 } else if (!strncasecmp(chan->language, "he", 2)) {
08105 return ast_play_and_wait(chan, box);
08106 } else if (!strncasecmp(chan->language, "pl", 2)) {
08107 return vm_play_folder_name_pl(chan, box);
08108 } else if (!strncasecmp(chan->language, "ua", 2)) {
08109 return vm_play_folder_name_ua(chan, box);
08110 } else if (!strncasecmp(chan->language, "vi", 2)) {
08111 return ast_play_and_wait(chan, box);
08112 } else {
08113 cmd = ast_play_and_wait(chan, box);
08114 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08115 }
08116 }
08117
08118
08119
08120
08121
08122
08123
08124
08125
08126
08127
08128
08129
08130 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08131 {
08132 int res = 0;
08133
08134 if (vms->newmessages) {
08135 res = ast_play_and_wait(chan, "vm-youhave");
08136 if (!res)
08137 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08138 if (!res) {
08139 if ((vms->newmessages == 1)) {
08140 res = ast_play_and_wait(chan, "vm-INBOX");
08141 if (!res)
08142 res = ast_play_and_wait(chan, "vm-message");
08143 } else {
08144 res = ast_play_and_wait(chan, "vm-INBOXs");
08145 if (!res)
08146 res = ast_play_and_wait(chan, "vm-messages");
08147 }
08148 }
08149 } else if (vms->oldmessages){
08150 res = ast_play_and_wait(chan, "vm-youhave");
08151 if (!res)
08152 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08153 if ((vms->oldmessages == 1)){
08154 res = ast_play_and_wait(chan, "vm-Old");
08155 if (!res)
08156 res = ast_play_and_wait(chan, "vm-message");
08157 } else {
08158 res = ast_play_and_wait(chan, "vm-Olds");
08159 if (!res)
08160 res = ast_play_and_wait(chan, "vm-messages");
08161 }
08162 } else if (!vms->oldmessages && !vms->newmessages)
08163 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08164 return res;
08165 }
08166
08167
08168
08169
08170
08171
08172
08173
08174
08175
08176
08177
08178
08179
08180
08181
08182
08183
08184
08185
08186
08187
08188
08189
08190
08191
08192
08193
08194
08195
08196
08197
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 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08225 {
08226 int res;
08227 int lastnum = 0;
08228
08229 res = ast_play_and_wait(chan, "vm-youhave");
08230
08231 if (!res && vms->newmessages) {
08232 lastnum = vms->newmessages;
08233
08234 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08235 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08236 }
08237
08238 if (!res && vms->oldmessages) {
08239 res = ast_play_and_wait(chan, "vm-and");
08240 }
08241 }
08242
08243 if (!res && vms->oldmessages) {
08244 lastnum = vms->oldmessages;
08245
08246 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08247 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08248 }
08249 }
08250
08251 if (!res) {
08252 if (lastnum == 0) {
08253 res = ast_play_and_wait(chan, "vm-no");
08254 }
08255 if (!res) {
08256 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08257 }
08258 }
08259
08260 return res;
08261 }
08262
08263
08264 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08265 {
08266 int res = 0;
08267
08268
08269 if (!res) {
08270 if ((vms->newmessages) || (vms->oldmessages)) {
08271 res = ast_play_and_wait(chan, "vm-youhave");
08272 }
08273
08274
08275
08276
08277
08278 if (vms->newmessages) {
08279 if (!res) {
08280 if (vms->newmessages == 1) {
08281 res = ast_play_and_wait(chan, "vm-INBOX1");
08282 } else {
08283 if (vms->newmessages == 2) {
08284 res = ast_play_and_wait(chan, "vm-shtei");
08285 } else {
08286 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08287 }
08288 res = ast_play_and_wait(chan, "vm-INBOX");
08289 }
08290 }
08291 if (vms->oldmessages && !res) {
08292 res = ast_play_and_wait(chan, "vm-and");
08293 if (vms->oldmessages == 1) {
08294 res = ast_play_and_wait(chan, "vm-Old1");
08295 } else {
08296 if (vms->oldmessages == 2) {
08297 res = ast_play_and_wait(chan, "vm-shtei");
08298 } else {
08299 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08300 }
08301 res = ast_play_and_wait(chan, "vm-Old");
08302 }
08303 }
08304 }
08305 if (!res && vms->oldmessages && !vms->newmessages) {
08306 if (!res) {
08307 if (vms->oldmessages == 1) {
08308 res = ast_play_and_wait(chan, "vm-Old1");
08309 } else {
08310 if (vms->oldmessages == 2) {
08311 res = ast_play_and_wait(chan, "vm-shtei");
08312 } else {
08313 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08314 }
08315 res = ast_play_and_wait(chan, "vm-Old");
08316 }
08317 }
08318 }
08319 if (!res) {
08320 if (!vms->oldmessages && !vms->newmessages) {
08321 if (!res) {
08322 res = ast_play_and_wait(chan, "vm-nomessages");
08323 }
08324 }
08325 }
08326 }
08327 return res;
08328 }
08329
08330
08331 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08332 {
08333 int res;
08334
08335
08336 res = ast_play_and_wait(chan, "vm-youhave");
08337 if (!res) {
08338 if (vms->urgentmessages) {
08339 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08340 if (!res)
08341 res = ast_play_and_wait(chan, "vm-Urgent");
08342 if ((vms->oldmessages || vms->newmessages) && !res) {
08343 res = ast_play_and_wait(chan, "vm-and");
08344 } else if (!res) {
08345 if ((vms->urgentmessages == 1))
08346 res = ast_play_and_wait(chan, "vm-message");
08347 else
08348 res = ast_play_and_wait(chan, "vm-messages");
08349 }
08350 }
08351 if (vms->newmessages) {
08352 res = say_and_wait(chan, vms->newmessages, chan->language);
08353 if (!res)
08354 res = ast_play_and_wait(chan, "vm-INBOX");
08355 if (vms->oldmessages && !res)
08356 res = ast_play_and_wait(chan, "vm-and");
08357 else if (!res) {
08358 if ((vms->newmessages == 1))
08359 res = ast_play_and_wait(chan, "vm-message");
08360 else
08361 res = ast_play_and_wait(chan, "vm-messages");
08362 }
08363
08364 }
08365 if (!res && vms->oldmessages) {
08366 res = say_and_wait(chan, vms->oldmessages, chan->language);
08367 if (!res)
08368 res = ast_play_and_wait(chan, "vm-Old");
08369 if (!res) {
08370 if (vms->oldmessages == 1)
08371 res = ast_play_and_wait(chan, "vm-message");
08372 else
08373 res = ast_play_and_wait(chan, "vm-messages");
08374 }
08375 }
08376 if (!res) {
08377 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08378 res = ast_play_and_wait(chan, "vm-no");
08379 if (!res)
08380 res = ast_play_and_wait(chan, "vm-messages");
08381 }
08382 }
08383 }
08384 return res;
08385 }
08386
08387
08388 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08389 {
08390
08391 int res;
08392 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08393 res = ast_play_and_wait(chan, "vm-no") ||
08394 ast_play_and_wait(chan, "vm-message");
08395 else
08396 res = ast_play_and_wait(chan, "vm-youhave");
08397 if (!res && vms->newmessages) {
08398 res = (vms->newmessages == 1) ?
08399 ast_play_and_wait(chan, "digits/un") ||
08400 ast_play_and_wait(chan, "vm-nuovo") ||
08401 ast_play_and_wait(chan, "vm-message") :
08402
08403 say_and_wait(chan, vms->newmessages, chan->language) ||
08404 ast_play_and_wait(chan, "vm-nuovi") ||
08405 ast_play_and_wait(chan, "vm-messages");
08406 if (!res && vms->oldmessages)
08407 res = ast_play_and_wait(chan, "vm-and");
08408 }
08409 if (!res && vms->oldmessages) {
08410 res = (vms->oldmessages == 1) ?
08411 ast_play_and_wait(chan, "digits/un") ||
08412 ast_play_and_wait(chan, "vm-vecchio") ||
08413 ast_play_and_wait(chan, "vm-message") :
08414
08415 say_and_wait(chan, vms->oldmessages, chan->language) ||
08416 ast_play_and_wait(chan, "vm-vecchi") ||
08417 ast_play_and_wait(chan, "vm-messages");
08418 }
08419 return res;
08420 }
08421
08422
08423 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08424 {
08425
08426 int res;
08427 div_t num;
08428
08429 if (!vms->oldmessages && !vms->newmessages) {
08430 res = ast_play_and_wait(chan, "vm-no");
08431 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08432 return res;
08433 } else {
08434 res = ast_play_and_wait(chan, "vm-youhave");
08435 }
08436
08437 if (vms->newmessages) {
08438 num = div(vms->newmessages, 10);
08439 if (vms->newmessages == 1) {
08440 res = ast_play_and_wait(chan, "digits/1-a");
08441 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08442 res = res ? res : ast_play_and_wait(chan, "vm-message");
08443 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08444 if (num.rem == 2) {
08445 if (!num.quot) {
08446 res = ast_play_and_wait(chan, "digits/2-ie");
08447 } else {
08448 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08449 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08450 }
08451 } else {
08452 res = say_and_wait(chan, vms->newmessages, chan->language);
08453 }
08454 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08455 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08456 } else {
08457 res = say_and_wait(chan, vms->newmessages, chan->language);
08458 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08459 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08460 }
08461 if (!res && vms->oldmessages)
08462 res = ast_play_and_wait(chan, "vm-and");
08463 }
08464 if (!res && vms->oldmessages) {
08465 num = div(vms->oldmessages, 10);
08466 if (vms->oldmessages == 1) {
08467 res = ast_play_and_wait(chan, "digits/1-a");
08468 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08469 res = res ? res : ast_play_and_wait(chan, "vm-message");
08470 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08471 if (num.rem == 2) {
08472 if (!num.quot) {
08473 res = ast_play_and_wait(chan, "digits/2-ie");
08474 } else {
08475 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08476 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08477 }
08478 } else {
08479 res = say_and_wait(chan, vms->oldmessages, chan->language);
08480 }
08481 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08482 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08483 } else {
08484 res = say_and_wait(chan, vms->oldmessages, chan->language);
08485 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08486 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08487 }
08488 }
08489
08490 return res;
08491 }
08492
08493
08494 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08495 {
08496
08497 int res;
08498
08499 res = ast_play_and_wait(chan, "vm-youhave");
08500 if (res)
08501 return res;
08502
08503 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08504 res = ast_play_and_wait(chan, "vm-no");
08505 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08506 return res;
08507 }
08508
08509 if (vms->newmessages) {
08510 if ((vms->newmessages == 1)) {
08511 res = ast_play_and_wait(chan, "digits/ett");
08512 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08513 res = res ? res : ast_play_and_wait(chan, "vm-message");
08514 } else {
08515 res = say_and_wait(chan, vms->newmessages, chan->language);
08516 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08517 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08518 }
08519 if (!res && vms->oldmessages)
08520 res = ast_play_and_wait(chan, "vm-and");
08521 }
08522 if (!res && vms->oldmessages) {
08523 if (vms->oldmessages == 1) {
08524 res = ast_play_and_wait(chan, "digits/ett");
08525 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08526 res = res ? res : ast_play_and_wait(chan, "vm-message");
08527 } else {
08528 res = say_and_wait(chan, vms->oldmessages, chan->language);
08529 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08530 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08531 }
08532 }
08533
08534 return res;
08535 }
08536
08537
08538 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08539 {
08540
08541 int res;
08542
08543 res = ast_play_and_wait(chan, "vm-youhave");
08544 if (res)
08545 return res;
08546
08547 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08548 res = ast_play_and_wait(chan, "vm-no");
08549 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08550 return res;
08551 }
08552
08553 if (vms->newmessages) {
08554 if ((vms->newmessages == 1)) {
08555 res = ast_play_and_wait(chan, "digits/1");
08556 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08557 res = res ? res : ast_play_and_wait(chan, "vm-message");
08558 } else {
08559 res = say_and_wait(chan, vms->newmessages, chan->language);
08560 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08561 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08562 }
08563 if (!res && vms->oldmessages)
08564 res = ast_play_and_wait(chan, "vm-and");
08565 }
08566 if (!res && vms->oldmessages) {
08567 if (vms->oldmessages == 1) {
08568 res = ast_play_and_wait(chan, "digits/1");
08569 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08570 res = res ? res : ast_play_and_wait(chan, "vm-message");
08571 } else {
08572 res = say_and_wait(chan, vms->oldmessages, chan->language);
08573 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08574 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08575 }
08576 }
08577
08578 return res;
08579 }
08580
08581
08582 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08583 {
08584
08585 int res;
08586 res = ast_play_and_wait(chan, "vm-youhave");
08587 if (!res) {
08588 if (vms->newmessages) {
08589 if ((vms->newmessages == 1))
08590 res = ast_play_and_wait(chan, "digits/1F");
08591 else
08592 res = say_and_wait(chan, vms->newmessages, chan->language);
08593 if (!res)
08594 res = ast_play_and_wait(chan, "vm-INBOX");
08595 if (vms->oldmessages && !res)
08596 res = ast_play_and_wait(chan, "vm-and");
08597 else if (!res) {
08598 if ((vms->newmessages == 1))
08599 res = ast_play_and_wait(chan, "vm-message");
08600 else
08601 res = ast_play_and_wait(chan, "vm-messages");
08602 }
08603
08604 }
08605 if (!res && vms->oldmessages) {
08606 if (vms->oldmessages == 1)
08607 res = ast_play_and_wait(chan, "digits/1F");
08608 else
08609 res = say_and_wait(chan, vms->oldmessages, chan->language);
08610 if (!res)
08611 res = ast_play_and_wait(chan, "vm-Old");
08612 if (!res) {
08613 if (vms->oldmessages == 1)
08614 res = ast_play_and_wait(chan, "vm-message");
08615 else
08616 res = ast_play_and_wait(chan, "vm-messages");
08617 }
08618 }
08619 if (!res) {
08620 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08621 res = ast_play_and_wait(chan, "vm-no");
08622 if (!res)
08623 res = ast_play_and_wait(chan, "vm-messages");
08624 }
08625 }
08626 }
08627 return res;
08628 }
08629
08630
08631 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08632 {
08633
08634 int res;
08635 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08636 res = ast_play_and_wait(chan, "vm-youhaveno");
08637 if (!res)
08638 res = ast_play_and_wait(chan, "vm-messages");
08639 } else {
08640 res = ast_play_and_wait(chan, "vm-youhave");
08641 }
08642 if (!res) {
08643 if (vms->newmessages) {
08644 if (!res) {
08645 if ((vms->newmessages == 1)) {
08646 res = ast_play_and_wait(chan, "digits/1M");
08647 if (!res)
08648 res = ast_play_and_wait(chan, "vm-message");
08649 if (!res)
08650 res = ast_play_and_wait(chan, "vm-INBOXs");
08651 } else {
08652 res = say_and_wait(chan, vms->newmessages, chan->language);
08653 if (!res)
08654 res = ast_play_and_wait(chan, "vm-messages");
08655 if (!res)
08656 res = ast_play_and_wait(chan, "vm-INBOX");
08657 }
08658 }
08659 if (vms->oldmessages && !res)
08660 res = ast_play_and_wait(chan, "vm-and");
08661 }
08662 if (vms->oldmessages) {
08663 if (!res) {
08664 if (vms->oldmessages == 1) {
08665 res = ast_play_and_wait(chan, "digits/1M");
08666 if (!res)
08667 res = ast_play_and_wait(chan, "vm-message");
08668 if (!res)
08669 res = ast_play_and_wait(chan, "vm-Olds");
08670 } else {
08671 res = say_and_wait(chan, vms->oldmessages, chan->language);
08672 if (!res)
08673 res = ast_play_and_wait(chan, "vm-messages");
08674 if (!res)
08675 res = ast_play_and_wait(chan, "vm-Old");
08676 }
08677 }
08678 }
08679 }
08680 return res;
08681 }
08682
08683
08684 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08685
08686 int res;
08687 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08688 res = ast_play_and_wait(chan, "vm-nomessages");
08689 return res;
08690 } else {
08691 res = ast_play_and_wait(chan, "vm-youhave");
08692 }
08693 if (vms->newmessages) {
08694 if (!res)
08695 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08696 if ((vms->newmessages == 1)) {
08697 if (!res)
08698 res = ast_play_and_wait(chan, "vm-message");
08699 if (!res)
08700 res = ast_play_and_wait(chan, "vm-INBOXs");
08701 } else {
08702 if (!res)
08703 res = ast_play_and_wait(chan, "vm-messages");
08704 if (!res)
08705 res = ast_play_and_wait(chan, "vm-INBOX");
08706 }
08707 if (vms->oldmessages && !res)
08708 res = ast_play_and_wait(chan, "vm-and");
08709 }
08710 if (vms->oldmessages) {
08711 if (!res)
08712 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08713 if (vms->oldmessages == 1) {
08714 if (!res)
08715 res = ast_play_and_wait(chan, "vm-message");
08716 if (!res)
08717 res = ast_play_and_wait(chan, "vm-Olds");
08718 } else {
08719 if (!res)
08720 res = ast_play_and_wait(chan, "vm-messages");
08721 if (!res)
08722 res = ast_play_and_wait(chan, "vm-Old");
08723 }
08724 }
08725 return res;
08726 }
08727
08728
08729 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08730 {
08731
08732 int res;
08733 res = ast_play_and_wait(chan, "vm-youhave");
08734 if (!res) {
08735 if (vms->newmessages) {
08736 res = say_and_wait(chan, vms->newmessages, chan->language);
08737 if (!res)
08738 res = ast_play_and_wait(chan, "vm-INBOX");
08739 if (vms->oldmessages && !res)
08740 res = ast_play_and_wait(chan, "vm-and");
08741 else if (!res) {
08742 if ((vms->newmessages == 1))
08743 res = ast_play_and_wait(chan, "vm-message");
08744 else
08745 res = ast_play_and_wait(chan, "vm-messages");
08746 }
08747
08748 }
08749 if (!res && vms->oldmessages) {
08750 res = say_and_wait(chan, vms->oldmessages, chan->language);
08751 if (!res)
08752 res = ast_play_and_wait(chan, "vm-Old");
08753 if (!res) {
08754 if (vms->oldmessages == 1)
08755 res = ast_play_and_wait(chan, "vm-message");
08756 else
08757 res = ast_play_and_wait(chan, "vm-messages");
08758 }
08759 }
08760 if (!res) {
08761 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08762 res = ast_play_and_wait(chan, "vm-no");
08763 if (!res)
08764 res = ast_play_and_wait(chan, "vm-messages");
08765 }
08766 }
08767 }
08768 return res;
08769 }
08770
08771
08772 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08773 {
08774
08775 int res;
08776 res = ast_play_and_wait(chan, "vm-youhave");
08777 if (!res) {
08778 if (vms->newmessages) {
08779 res = say_and_wait(chan, vms->newmessages, chan->language);
08780 if (!res) {
08781 if (vms->newmessages == 1)
08782 res = ast_play_and_wait(chan, "vm-INBOXs");
08783 else
08784 res = ast_play_and_wait(chan, "vm-INBOX");
08785 }
08786 if (vms->oldmessages && !res)
08787 res = ast_play_and_wait(chan, "vm-and");
08788 else if (!res) {
08789 if ((vms->newmessages == 1))
08790 res = ast_play_and_wait(chan, "vm-message");
08791 else
08792 res = ast_play_and_wait(chan, "vm-messages");
08793 }
08794
08795 }
08796 if (!res && vms->oldmessages) {
08797 res = say_and_wait(chan, vms->oldmessages, chan->language);
08798 if (!res) {
08799 if (vms->oldmessages == 1)
08800 res = ast_play_and_wait(chan, "vm-Olds");
08801 else
08802 res = ast_play_and_wait(chan, "vm-Old");
08803 }
08804 if (!res) {
08805 if (vms->oldmessages == 1)
08806 res = ast_play_and_wait(chan, "vm-message");
08807 else
08808 res = ast_play_and_wait(chan, "vm-messages");
08809 }
08810 }
08811 if (!res) {
08812 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08813 res = ast_play_and_wait(chan, "vm-no");
08814 if (!res)
08815 res = ast_play_and_wait(chan, "vm-messages");
08816 }
08817 }
08818 }
08819 return res;
08820 }
08821
08822
08823 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08824 {
08825
08826 int res;
08827 res = ast_play_and_wait(chan, "vm-youhave");
08828 if (!res) {
08829 if (vms->newmessages) {
08830 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08831 if (!res) {
08832 if ((vms->newmessages == 1)) {
08833 res = ast_play_and_wait(chan, "vm-message");
08834 if (!res)
08835 res = ast_play_and_wait(chan, "vm-INBOXs");
08836 } else {
08837 res = ast_play_and_wait(chan, "vm-messages");
08838 if (!res)
08839 res = ast_play_and_wait(chan, "vm-INBOX");
08840 }
08841 }
08842 if (vms->oldmessages && !res)
08843 res = ast_play_and_wait(chan, "vm-and");
08844 }
08845 if (!res && vms->oldmessages) {
08846 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08847 if (!res) {
08848 if (vms->oldmessages == 1) {
08849 res = ast_play_and_wait(chan, "vm-message");
08850 if (!res)
08851 res = ast_play_and_wait(chan, "vm-Olds");
08852 } else {
08853 res = ast_play_and_wait(chan, "vm-messages");
08854 if (!res)
08855 res = ast_play_and_wait(chan, "vm-Old");
08856 }
08857 }
08858 }
08859 if (!res) {
08860 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08861 res = ast_play_and_wait(chan, "vm-no");
08862 if (!res)
08863 res = ast_play_and_wait(chan, "vm-messages");
08864 }
08865 }
08866 }
08867 return res;
08868 }
08869
08870
08871
08872
08873
08874
08875
08876
08877
08878
08879
08880
08881
08882
08883
08884
08885
08886 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08887 {
08888 int res;
08889 res = ast_play_and_wait(chan, "vm-youhave");
08890 if (!res) {
08891 if (vms->newmessages) {
08892 if (vms->newmessages == 1) {
08893 res = ast_play_and_wait(chan, "digits/jednu");
08894 } else {
08895 res = say_and_wait(chan, vms->newmessages, chan->language);
08896 }
08897 if (!res) {
08898 if ((vms->newmessages == 1))
08899 res = ast_play_and_wait(chan, "vm-novou");
08900 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08901 res = ast_play_and_wait(chan, "vm-nove");
08902 if (vms->newmessages > 4)
08903 res = ast_play_and_wait(chan, "vm-novych");
08904 }
08905 if (vms->oldmessages && !res)
08906 res = ast_play_and_wait(chan, "vm-and");
08907 else if (!res) {
08908 if ((vms->newmessages == 1))
08909 res = ast_play_and_wait(chan, "vm-zpravu");
08910 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08911 res = ast_play_and_wait(chan, "vm-zpravy");
08912 if (vms->newmessages > 4)
08913 res = ast_play_and_wait(chan, "vm-zprav");
08914 }
08915 }
08916 if (!res && vms->oldmessages) {
08917 res = say_and_wait(chan, vms->oldmessages, chan->language);
08918 if (!res) {
08919 if ((vms->oldmessages == 1))
08920 res = ast_play_and_wait(chan, "vm-starou");
08921 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08922 res = ast_play_and_wait(chan, "vm-stare");
08923 if (vms->oldmessages > 4)
08924 res = ast_play_and_wait(chan, "vm-starych");
08925 }
08926 if (!res) {
08927 if ((vms->oldmessages == 1))
08928 res = ast_play_and_wait(chan, "vm-zpravu");
08929 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08930 res = ast_play_and_wait(chan, "vm-zpravy");
08931 if (vms->oldmessages > 4)
08932 res = ast_play_and_wait(chan, "vm-zprav");
08933 }
08934 }
08935 if (!res) {
08936 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08937 res = ast_play_and_wait(chan, "vm-no");
08938 if (!res)
08939 res = ast_play_and_wait(chan, "vm-zpravy");
08940 }
08941 }
08942 }
08943 return res;
08944 }
08945
08946
08947 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08948 {
08949 int res;
08950
08951 res = ast_play_and_wait(chan, "vm-you");
08952
08953 if (!res && vms->newmessages) {
08954 res = ast_play_and_wait(chan, "vm-have");
08955 if (!res)
08956 res = say_and_wait(chan, vms->newmessages, chan->language);
08957 if (!res)
08958 res = ast_play_and_wait(chan, "vm-tong");
08959 if (!res)
08960 res = ast_play_and_wait(chan, "vm-INBOX");
08961 if (vms->oldmessages && !res)
08962 res = ast_play_and_wait(chan, "vm-and");
08963 else if (!res)
08964 res = ast_play_and_wait(chan, "vm-messages");
08965 }
08966 if (!res && vms->oldmessages) {
08967 res = ast_play_and_wait(chan, "vm-have");
08968 if (!res)
08969 res = say_and_wait(chan, vms->oldmessages, chan->language);
08970 if (!res)
08971 res = ast_play_and_wait(chan, "vm-tong");
08972 if (!res)
08973 res = ast_play_and_wait(chan, "vm-Old");
08974 if (!res)
08975 res = ast_play_and_wait(chan, "vm-messages");
08976 }
08977 if (!res && !vms->oldmessages && !vms->newmessages) {
08978 res = ast_play_and_wait(chan, "vm-haveno");
08979 if (!res)
08980 res = ast_play_and_wait(chan, "vm-messages");
08981 }
08982 return res;
08983 }
08984
08985
08986 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
08987 {
08988 int res;
08989
08990
08991 res = ast_play_and_wait(chan, "vm-youhave");
08992 if (!res) {
08993 if (vms->newmessages) {
08994 res = say_and_wait(chan, vms->newmessages, chan->language);
08995 if (!res)
08996 res = ast_play_and_wait(chan, "vm-INBOX");
08997 if (vms->oldmessages && !res)
08998 res = ast_play_and_wait(chan, "vm-and");
08999 }
09000 if (!res && vms->oldmessages) {
09001 res = say_and_wait(chan, vms->oldmessages, chan->language);
09002 if (!res)
09003 res = ast_play_and_wait(chan, "vm-Old");
09004 }
09005 if (!res) {
09006 if (!vms->oldmessages && !vms->newmessages) {
09007 res = ast_play_and_wait(chan, "vm-no");
09008 if (!res)
09009 res = ast_play_and_wait(chan, "vm-message");
09010 }
09011 }
09012 }
09013 return res;
09014 }
09015
09016 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09017 {
09018 char prefile[256];
09019
09020
09021 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09022 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09023 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09024 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09025 ast_play_and_wait(chan, "vm-tempgreetactive");
09026 }
09027 DISPOSE(prefile, -1);
09028 }
09029
09030
09031 if (0) {
09032 return 0;
09033 } else if (!strncasecmp(chan->language, "cs", 2)) {
09034 return vm_intro_cs(chan, vms);
09035 } else if (!strncasecmp(chan->language, "cz", 2)) {
09036 static int deprecation_warning = 0;
09037 if (deprecation_warning++ % 10 == 0) {
09038 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09039 }
09040 return vm_intro_cs(chan, vms);
09041 } else if (!strncasecmp(chan->language, "de", 2)) {
09042 return vm_intro_de(chan, vms);
09043 } else if (!strncasecmp(chan->language, "es", 2)) {
09044 return vm_intro_es(chan, vms);
09045 } else if (!strncasecmp(chan->language, "fr", 2)) {
09046 return vm_intro_fr(chan, vms);
09047 } else if (!strncasecmp(chan->language, "gr", 2)) {
09048 return vm_intro_gr(chan, vms);
09049 } else if (!strncasecmp(chan->language, "he", 2)) {
09050 return vm_intro_he(chan, vms);
09051 } else if (!strncasecmp(chan->language, "it", 2)) {
09052 return vm_intro_it(chan, vms);
09053 } else if (!strncasecmp(chan->language, "nl", 2)) {
09054 return vm_intro_nl(chan, vms);
09055 } else if (!strncasecmp(chan->language, "no", 2)) {
09056 return vm_intro_no(chan, vms);
09057 } else if (!strncasecmp(chan->language, "pl", 2)) {
09058 return vm_intro_pl(chan, vms);
09059 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09060 return vm_intro_pt_BR(chan, vms);
09061 } else if (!strncasecmp(chan->language, "pt", 2)) {
09062 return vm_intro_pt(chan, vms);
09063 } else if (!strncasecmp(chan->language, "ru", 2)) {
09064 return vm_intro_multilang(chan, vms, "n");
09065 } else if (!strncasecmp(chan->language, "se", 2)) {
09066 return vm_intro_se(chan, vms);
09067 } else if (!strncasecmp(chan->language, "ua", 2)) {
09068 return vm_intro_multilang(chan, vms, "n");
09069 } else if (!strncasecmp(chan->language, "vi", 2)) {
09070 return vm_intro_vi(chan, vms);
09071 } else if (!strncasecmp(chan->language, "zh", 2)) {
09072 return vm_intro_zh(chan, vms);
09073 } else {
09074 return vm_intro_en(chan, vms);
09075 }
09076 }
09077
09078 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09079 {
09080 int res = 0;
09081
09082 while (!res) {
09083 if (vms->starting) {
09084 if (vms->lastmsg > -1) {
09085 if (skipadvanced)
09086 res = ast_play_and_wait(chan, "vm-onefor-full");
09087 else
09088 res = ast_play_and_wait(chan, "vm-onefor");
09089 if (!res)
09090 res = vm_play_folder_name(chan, vms->vmbox);
09091 }
09092 if (!res) {
09093 if (skipadvanced)
09094 res = ast_play_and_wait(chan, "vm-opts-full");
09095 else
09096 res = ast_play_and_wait(chan, "vm-opts");
09097 }
09098 } else {
09099
09100 if (skipadvanced) {
09101 res = ast_play_and_wait(chan, "vm-onefor-full");
09102 if (!res)
09103 res = vm_play_folder_name(chan, vms->vmbox);
09104 res = ast_play_and_wait(chan, "vm-opts-full");
09105 }
09106
09107
09108
09109
09110
09111
09112 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09113 res = ast_play_and_wait(chan, "vm-prev");
09114 }
09115 if (!res && !skipadvanced)
09116 res = ast_play_and_wait(chan, "vm-advopts");
09117 if (!res)
09118 res = ast_play_and_wait(chan, "vm-repeat");
09119
09120
09121
09122
09123
09124
09125 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09126 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09127 res = ast_play_and_wait(chan, "vm-next");
09128 }
09129 if (!res) {
09130 if (!vms->deleted[vms->curmsg])
09131 res = ast_play_and_wait(chan, "vm-delete");
09132 else
09133 res = ast_play_and_wait(chan, "vm-undelete");
09134 if (!res)
09135 res = ast_play_and_wait(chan, "vm-toforward");
09136 if (!res)
09137 res = ast_play_and_wait(chan, "vm-savemessage");
09138 }
09139 }
09140 if (!res) {
09141 res = ast_play_and_wait(chan, "vm-helpexit");
09142 }
09143 if (!res)
09144 res = ast_waitfordigit(chan, 6000);
09145 if (!res) {
09146 vms->repeats++;
09147 if (vms->repeats > 2) {
09148 res = 't';
09149 }
09150 }
09151 }
09152 return res;
09153 }
09154
09155 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09156 {
09157 int res = 0;
09158
09159 while (!res) {
09160 if (vms->lastmsg > -1) {
09161 res = ast_play_and_wait(chan, "vm-listen");
09162 if (!res)
09163 res = vm_play_folder_name(chan, vms->vmbox);
09164 if (!res)
09165 res = ast_play_and_wait(chan, "press");
09166 if (!res)
09167 res = ast_play_and_wait(chan, "digits/1");
09168 }
09169 if (!res)
09170 res = ast_play_and_wait(chan, "vm-opts");
09171 if (!res) {
09172 vms->starting = 0;
09173 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09174 }
09175 }
09176 return res;
09177 }
09178
09179 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09180 {
09181 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09182 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09183 } else {
09184 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09185 }
09186 }
09187
09188
09189 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09190 {
09191 int cmd = 0;
09192 int duration = 0;
09193 int tries = 0;
09194 char newpassword[80] = "";
09195 char newpassword2[80] = "";
09196 char prefile[PATH_MAX] = "";
09197 unsigned char buf[256];
09198 int bytes = 0;
09199
09200 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09201 if (ast_adsi_available(chan)) {
09202 bytes += adsi_logo(buf + bytes);
09203 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09204 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09205 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09206 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09207 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09208 }
09209
09210
09211 if (ast_test_flag(vmu, VM_FORCENAME)) {
09212 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09213 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09214 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09215 if (cmd < 0 || cmd == 't' || cmd == '#')
09216 return cmd;
09217 }
09218 }
09219
09220
09221 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09222 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09223 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09224 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09225 if (cmd < 0 || cmd == 't' || cmd == '#')
09226 return cmd;
09227 }
09228
09229 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09230 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09231 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09232 if (cmd < 0 || cmd == 't' || cmd == '#')
09233 return cmd;
09234 }
09235 }
09236
09237
09238
09239
09240
09241 for (;;) {
09242 newpassword[1] = '\0';
09243 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09244 if (cmd == '#')
09245 newpassword[0] = '\0';
09246 if (cmd < 0 || cmd == 't' || cmd == '#')
09247 return cmd;
09248 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09249 if (cmd < 0 || cmd == 't' || cmd == '#')
09250 return cmd;
09251 cmd = check_password(vmu, newpassword);
09252 if (cmd != 0) {
09253 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09254 cmd = ast_play_and_wait(chan, vm_invalid_password);
09255 } else {
09256 newpassword2[1] = '\0';
09257 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09258 if (cmd == '#')
09259 newpassword2[0] = '\0';
09260 if (cmd < 0 || cmd == 't' || cmd == '#')
09261 return cmd;
09262 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09263 if (cmd < 0 || cmd == 't' || cmd == '#')
09264 return cmd;
09265 if (!strcmp(newpassword, newpassword2))
09266 break;
09267 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09268 cmd = ast_play_and_wait(chan, vm_mismatch);
09269 }
09270 if (++tries == 3)
09271 return -1;
09272 if (cmd != 0) {
09273 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09274 }
09275 }
09276 if (pwdchange & PWDCHANGE_INTERNAL)
09277 vm_change_password(vmu, newpassword);
09278 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09279 vm_change_password_shell(vmu, newpassword);
09280
09281 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09282 cmd = ast_play_and_wait(chan, vm_passchanged);
09283
09284 return cmd;
09285 }
09286
09287 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09288 {
09289 int cmd = 0;
09290 int retries = 0;
09291 int duration = 0;
09292 char newpassword[80] = "";
09293 char newpassword2[80] = "";
09294 char prefile[PATH_MAX] = "";
09295 unsigned char buf[256];
09296 int bytes = 0;
09297
09298 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09299 if (ast_adsi_available(chan)) {
09300 bytes += adsi_logo(buf + bytes);
09301 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09302 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09303 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09304 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09305 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09306 }
09307 while ((cmd >= 0) && (cmd != 't')) {
09308 if (cmd)
09309 retries = 0;
09310 switch (cmd) {
09311 case '1':
09312 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09313 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09314 break;
09315 case '2':
09316 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09317 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09318 break;
09319 case '3':
09320 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09321 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09322 break;
09323 case '4':
09324 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09325 break;
09326 case '5':
09327 if (vmu->password[0] == '-') {
09328 cmd = ast_play_and_wait(chan, "vm-no");
09329 break;
09330 }
09331 newpassword[1] = '\0';
09332 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09333 if (cmd == '#')
09334 newpassword[0] = '\0';
09335 else {
09336 if (cmd < 0)
09337 break;
09338 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09339 break;
09340 }
09341 }
09342 cmd = check_password(vmu, newpassword);
09343 if (cmd != 0) {
09344 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09345 cmd = ast_play_and_wait(chan, vm_invalid_password);
09346 if (!cmd) {
09347 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09348 }
09349 break;
09350 }
09351 newpassword2[1] = '\0';
09352 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09353 if (cmd == '#')
09354 newpassword2[0] = '\0';
09355 else {
09356 if (cmd < 0)
09357 break;
09358
09359 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09360 break;
09361 }
09362 }
09363 if (strcmp(newpassword, newpassword2)) {
09364 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09365 cmd = ast_play_and_wait(chan, vm_mismatch);
09366 if (!cmd) {
09367 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09368 }
09369 break;
09370 }
09371
09372 if (pwdchange & PWDCHANGE_INTERNAL) {
09373 vm_change_password(vmu, newpassword);
09374 }
09375 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09376 vm_change_password_shell(vmu, newpassword);
09377 }
09378
09379 ast_debug(1, "User %s set password to %s of length %d\n",
09380 vms->username, newpassword, (int) strlen(newpassword));
09381 cmd = ast_play_and_wait(chan, vm_passchanged);
09382 break;
09383 case '*':
09384 cmd = 't';
09385 break;
09386 default:
09387 cmd = 0;
09388 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09389 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09390 if (ast_fileexists(prefile, NULL, NULL)) {
09391 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09392 }
09393 DISPOSE(prefile, -1);
09394 if (!cmd) {
09395 cmd = ast_play_and_wait(chan, "vm-options");
09396 }
09397 if (!cmd) {
09398 cmd = ast_waitfordigit(chan, 6000);
09399 }
09400 if (!cmd) {
09401 retries++;
09402 }
09403 if (retries > 3) {
09404 cmd = 't';
09405 }
09406 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09407 }
09408 }
09409 if (cmd == 't')
09410 cmd = 0;
09411 return cmd;
09412 }
09413
09414
09415
09416
09417
09418
09419
09420
09421
09422
09423
09424
09425
09426
09427
09428
09429
09430 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09431 {
09432 int cmd = 0;
09433 int retries = 0;
09434 int duration = 0;
09435 char prefile[PATH_MAX] = "";
09436 unsigned char buf[256];
09437 int bytes = 0;
09438
09439 if (ast_adsi_available(chan)) {
09440 bytes += adsi_logo(buf + bytes);
09441 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09442 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09443 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09444 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09445 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09446 }
09447
09448 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09449 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09450 while ((cmd >= 0) && (cmd != 't')) {
09451 if (cmd)
09452 retries = 0;
09453 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09454 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09455 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09456 cmd = 't';
09457 } else {
09458 switch (cmd) {
09459 case '1':
09460 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09461 break;
09462 case '2':
09463 DELETE(prefile, -1, prefile, vmu);
09464 ast_play_and_wait(chan, "vm-tempremoved");
09465 cmd = 't';
09466 break;
09467 case '*':
09468 cmd = 't';
09469 break;
09470 default:
09471 cmd = ast_play_and_wait(chan,
09472 ast_fileexists(prefile, NULL, NULL) > 0 ?
09473 "vm-tempgreeting2" : "vm-tempgreeting");
09474 if (!cmd) {
09475 cmd = ast_waitfordigit(chan, 6000);
09476 }
09477 if (!cmd) {
09478 retries++;
09479 }
09480 if (retries > 3) {
09481 cmd = 't';
09482 }
09483 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09484 }
09485 }
09486 DISPOSE(prefile, -1);
09487 }
09488 if (cmd == 't')
09489 cmd = 0;
09490 return cmd;
09491 }
09492
09493
09494
09495
09496
09497
09498
09499
09500
09501 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09502 {
09503 int cmd = 0;
09504
09505 if (vms->lastmsg > -1) {
09506 cmd = play_message(chan, vmu, vms);
09507 } else {
09508 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09509 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09510 if (!cmd) {
09511 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09512 cmd = ast_play_and_wait(chan, vms->fn);
09513 }
09514 if (!cmd)
09515 cmd = ast_play_and_wait(chan, "vm-messages");
09516 } else {
09517 if (!cmd)
09518 cmd = ast_play_and_wait(chan, "vm-messages");
09519 if (!cmd) {
09520 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09521 cmd = ast_play_and_wait(chan, vms->fn);
09522 }
09523 }
09524 }
09525 return cmd;
09526 }
09527
09528
09529 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09530 {
09531 int cmd = 0;
09532
09533 if (vms->lastmsg > -1) {
09534 cmd = play_message(chan, vmu, vms);
09535 } else {
09536 if (!strcasecmp(vms->fn, "INBOX")) {
09537 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09538 } else {
09539 cmd = ast_play_and_wait(chan, "vm-nomessages");
09540 }
09541 }
09542 return cmd;
09543 }
09544
09545
09546
09547
09548
09549
09550
09551
09552
09553 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09554 {
09555 int cmd = 0;
09556
09557 if (vms->lastmsg > -1) {
09558 cmd = play_message(chan, vmu, vms);
09559 } else {
09560 cmd = ast_play_and_wait(chan, "vm-youhave");
09561 if (!cmd)
09562 cmd = ast_play_and_wait(chan, "vm-no");
09563 if (!cmd) {
09564 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09565 cmd = ast_play_and_wait(chan, vms->fn);
09566 }
09567 if (!cmd)
09568 cmd = ast_play_and_wait(chan, "vm-messages");
09569 }
09570 return cmd;
09571 }
09572
09573
09574
09575
09576
09577
09578
09579
09580
09581 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09582 {
09583 int cmd;
09584
09585 if (vms->lastmsg > -1) {
09586 cmd = play_message(chan, vmu, vms);
09587 } else {
09588 cmd = ast_play_and_wait(chan, "vm-no");
09589 if (!cmd)
09590 cmd = ast_play_and_wait(chan, "vm-message");
09591 if (!cmd) {
09592 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09593 cmd = ast_play_and_wait(chan, vms->fn);
09594 }
09595 }
09596 return cmd;
09597 }
09598
09599
09600
09601
09602
09603
09604
09605
09606
09607 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09608 {
09609 int cmd;
09610
09611 if (vms->lastmsg > -1) {
09612 cmd = play_message(chan, vmu, vms);
09613 } else {
09614 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09615 if (!cmd)
09616 cmd = ast_play_and_wait(chan, "vm-messages");
09617 if (!cmd) {
09618 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09619 cmd = ast_play_and_wait(chan, vms->fn);
09620 }
09621 }
09622 return cmd;
09623 }
09624
09625
09626
09627
09628
09629
09630
09631
09632
09633 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09634 {
09635 int cmd;
09636
09637 if (vms->lastmsg > -1) {
09638 cmd = play_message(chan, vmu, vms);
09639 } else {
09640 cmd = ast_play_and_wait(chan, "vm-no");
09641 if (!cmd) {
09642 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09643 cmd = ast_play_and_wait(chan, vms->fn);
09644 }
09645 if (!cmd)
09646 cmd = ast_play_and_wait(chan, "vm-messages");
09647 }
09648 return cmd;
09649 }
09650
09651
09652
09653
09654
09655
09656
09657
09658
09659 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09660 {
09661 int cmd;
09662
09663 if (vms->lastmsg > -1) {
09664 cmd = play_message(chan, vmu, vms);
09665 } else {
09666 cmd = ast_play_and_wait(chan, "vm-you");
09667 if (!cmd)
09668 cmd = ast_play_and_wait(chan, "vm-haveno");
09669 if (!cmd)
09670 cmd = ast_play_and_wait(chan, "vm-messages");
09671 if (!cmd) {
09672 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09673 cmd = ast_play_and_wait(chan, vms->fn);
09674 }
09675 }
09676 return cmd;
09677 }
09678
09679
09680
09681
09682
09683
09684
09685
09686
09687 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09688 {
09689 int cmd = 0;
09690
09691 if (vms->lastmsg > -1) {
09692 cmd = play_message(chan, vmu, vms);
09693 } else {
09694 cmd = ast_play_and_wait(chan, "vm-no");
09695 if (!cmd) {
09696 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09697 cmd = ast_play_and_wait(chan, vms->fn);
09698 }
09699 }
09700 return cmd;
09701 }
09702
09703
09704
09705
09706
09707
09708
09709
09710
09711
09712
09713
09714 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09715 {
09716 if (!strncasecmp(chan->language, "es", 2)) {
09717 return vm_browse_messages_es(chan, vms, vmu);
09718 } else if (!strncasecmp(chan->language, "gr", 2)) {
09719 return vm_browse_messages_gr(chan, vms, vmu);
09720 } else if (!strncasecmp(chan->language, "he", 2)) {
09721 return vm_browse_messages_he(chan, vms, vmu);
09722 } else if (!strncasecmp(chan->language, "it", 2)) {
09723 return vm_browse_messages_it(chan, vms, vmu);
09724 } else if (!strncasecmp(chan->language, "pt", 2)) {
09725 return vm_browse_messages_pt(chan, vms, vmu);
09726 } else if (!strncasecmp(chan->language, "vi", 2)) {
09727 return vm_browse_messages_vi(chan, vms, vmu);
09728 } else if (!strncasecmp(chan->language, "zh", 2)) {
09729 return vm_browse_messages_zh(chan, vms, vmu);
09730 } else {
09731 return vm_browse_messages_en(chan, vms, vmu);
09732 }
09733 }
09734
09735 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09736 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09737 int skipuser, int max_logins, int silent)
09738 {
09739 int useadsi = 0, valid = 0, logretries = 0;
09740 char password[AST_MAX_EXTENSION]="", *passptr;
09741 struct ast_vm_user vmus, *vmu = NULL;
09742
09743
09744 adsi_begin(chan, &useadsi);
09745 if (!skipuser && useadsi)
09746 adsi_login(chan);
09747 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09748 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09749 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09750 return -1;
09751 }
09752
09753
09754
09755 while (!valid && (logretries < max_logins)) {
09756
09757 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09758 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09759 return -1;
09760 }
09761 if (ast_strlen_zero(mailbox)) {
09762 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09763 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09764 } else {
09765 ast_verb(3, "Username not entered\n");
09766 return -1;
09767 }
09768 } else if (mailbox[0] == '*') {
09769
09770 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09771 if (ast_exists_extension(chan, chan->context, "a", 1,
09772 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09773 return -1;
09774 }
09775 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09776 mailbox[0] = '\0';
09777 }
09778
09779 if (useadsi)
09780 adsi_password(chan);
09781
09782 if (!ast_strlen_zero(prefix)) {
09783 char fullusername[80] = "";
09784 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09785 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09786 ast_copy_string(mailbox, fullusername, mailbox_size);
09787 }
09788
09789 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09790 vmu = find_user(&vmus, context, mailbox);
09791 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09792
09793 password[0] = '\0';
09794 } else {
09795 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09796 if (ast_streamfile(chan, vm_password, chan->language)) {
09797 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09798 return -1;
09799 }
09800 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09801 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09802 return -1;
09803 } else if (password[0] == '*') {
09804
09805 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09806 if (ast_exists_extension(chan, chan->context, "a", 1,
09807 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09808 mailbox[0] = '*';
09809 return -1;
09810 }
09811 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09812 mailbox[0] = '\0';
09813
09814 vmu = NULL;
09815 }
09816 }
09817
09818 if (vmu) {
09819 passptr = vmu->password;
09820 if (passptr[0] == '-') passptr++;
09821 }
09822 if (vmu && !strcmp(passptr, password))
09823 valid++;
09824 else {
09825 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09826 if (!ast_strlen_zero(prefix))
09827 mailbox[0] = '\0';
09828 }
09829 logretries++;
09830 if (!valid) {
09831 if (skipuser || logretries >= max_logins) {
09832 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09833 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09834 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09835 return -1;
09836 }
09837 } else {
09838 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09839 if (useadsi)
09840 adsi_login(chan);
09841 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09842 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09843 return -1;
09844 }
09845 }
09846 if (ast_waitstream(chan, ""))
09847 return -1;
09848 }
09849 }
09850 if (!valid && (logretries >= max_logins)) {
09851 ast_stopstream(chan);
09852 ast_play_and_wait(chan, "vm-goodbye");
09853 return -1;
09854 }
09855 if (vmu && !skipuser) {
09856 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09857 }
09858 return 0;
09859 }
09860
09861 static int vm_execmain(struct ast_channel *chan, const char *data)
09862 {
09863
09864
09865
09866 int res = -1;
09867 int cmd = 0;
09868 int valid = 0;
09869 char prefixstr[80] ="";
09870 char ext_context[256]="";
09871 int box;
09872 int useadsi = 0;
09873 int skipuser = 0;
09874 struct vm_state vms;
09875 struct ast_vm_user *vmu = NULL, vmus;
09876 char *context = NULL;
09877 int silentexit = 0;
09878 struct ast_flags flags = { 0 };
09879 signed char record_gain = 0;
09880 int play_auto = 0;
09881 int play_folder = 0;
09882 int in_urgent = 0;
09883 #ifdef IMAP_STORAGE
09884 int deleted = 0;
09885 #endif
09886
09887
09888 memset(&vms, 0, sizeof(vms));
09889
09890 vms.lastmsg = -1;
09891
09892 memset(&vmus, 0, sizeof(vmus));
09893
09894 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09895 if (chan->_state != AST_STATE_UP) {
09896 ast_debug(1, "Before ast_answer\n");
09897 ast_answer(chan);
09898 }
09899
09900 if (!ast_strlen_zero(data)) {
09901 char *opts[OPT_ARG_ARRAY_SIZE];
09902 char *parse;
09903 AST_DECLARE_APP_ARGS(args,
09904 AST_APP_ARG(argv0);
09905 AST_APP_ARG(argv1);
09906 );
09907
09908 parse = ast_strdupa(data);
09909
09910 AST_STANDARD_APP_ARGS(args, parse);
09911
09912 if (args.argc == 2) {
09913 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09914 return -1;
09915 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09916 int gain;
09917 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09918 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09919 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09920 return -1;
09921 } else {
09922 record_gain = (signed char) gain;
09923 }
09924 } else {
09925 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09926 }
09927 }
09928 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09929 play_auto = 1;
09930 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09931
09932 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09933 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09934 play_folder = -1;
09935 }
09936 } else {
09937 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09938 }
09939 } else {
09940 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09941 }
09942 if (play_folder > 9 || play_folder < 0) {
09943 ast_log(AST_LOG_WARNING,
09944 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09945 opts[OPT_ARG_PLAYFOLDER]);
09946 play_folder = 0;
09947 }
09948 }
09949 } else {
09950
09951 while (*(args.argv0)) {
09952 if (*(args.argv0) == 's')
09953 ast_set_flag(&flags, OPT_SILENT);
09954 else if (*(args.argv0) == 'p')
09955 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09956 else
09957 break;
09958 (args.argv0)++;
09959 }
09960
09961 }
09962
09963 valid = ast_test_flag(&flags, OPT_SILENT);
09964
09965 if ((context = strchr(args.argv0, '@')))
09966 *context++ = '\0';
09967
09968 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09969 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09970 else
09971 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09972
09973 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09974 skipuser++;
09975 else
09976 valid = 0;
09977 }
09978
09979 if (!valid)
09980 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09981
09982 ast_debug(1, "After vm_authenticate\n");
09983
09984 if (vms.username[0] == '*') {
09985 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09986
09987
09988 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
09989 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
09990 res = 0;
09991 goto out;
09992 }
09993 }
09994
09995 if (!res) {
09996 valid = 1;
09997 if (!skipuser)
09998 vmu = &vmus;
09999 } else {
10000 res = 0;
10001 }
10002
10003
10004 adsi_begin(chan, &useadsi);
10005
10006 ast_test_suite_assert(valid);
10007 if (!valid) {
10008 goto out;
10009 }
10010 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10011
10012 #ifdef IMAP_STORAGE
10013 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10014 pthread_setspecific(ts_vmstate.key, &vms);
10015
10016 vms.interactive = 1;
10017 vms.updated = 1;
10018 if (vmu)
10019 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10020 vmstate_insert(&vms);
10021 init_vm_state(&vms);
10022 #endif
10023
10024 if (!(vms.deleted = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
10025 ast_log(AST_LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
10026 cmd = ast_play_and_wait(chan, "an-error-has-occured");
10027 return -1;
10028 }
10029 if (!(vms.heard = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
10030 ast_log(AST_LOG_ERROR, "Could not allocate memory for heard message storage!\n");
10031 cmd = ast_play_and_wait(chan, "an-error-has-occured");
10032 return -1;
10033 }
10034
10035
10036 if (!ast_strlen_zero(vmu->language))
10037 ast_string_field_set(chan, language, vmu->language);
10038
10039
10040 ast_debug(1, "Before open_mailbox\n");
10041 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10042 if (res < 0)
10043 goto out;
10044 vms.oldmessages = vms.lastmsg + 1;
10045 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10046
10047 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10048 if (res < 0)
10049 goto out;
10050 vms.newmessages = vms.lastmsg + 1;
10051 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10052
10053 in_urgent = 1;
10054 res = open_mailbox(&vms, vmu, 11);
10055 if (res < 0)
10056 goto out;
10057 vms.urgentmessages = vms.lastmsg + 1;
10058 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10059
10060
10061 if (play_auto) {
10062 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10063 if (vms.urgentmessages) {
10064 in_urgent = 1;
10065 res = open_mailbox(&vms, vmu, 11);
10066 } else {
10067 in_urgent = 0;
10068 res = open_mailbox(&vms, vmu, play_folder);
10069 }
10070 if (res < 0)
10071 goto out;
10072
10073
10074 if (vms.lastmsg == -1) {
10075 in_urgent = 0;
10076 cmd = vm_browse_messages(chan, &vms, vmu);
10077 res = 0;
10078 goto out;
10079 }
10080 } else {
10081 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10082
10083 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10084 in_urgent = 0;
10085 play_folder = 1;
10086 if (res < 0)
10087 goto out;
10088 } else if (!vms.urgentmessages && vms.newmessages) {
10089
10090 in_urgent = 0;
10091 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10092 if (res < 0)
10093 goto out;
10094 }
10095 }
10096
10097 if (useadsi)
10098 adsi_status(chan, &vms);
10099 res = 0;
10100
10101
10102 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10103 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10104 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10105 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10106 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10107 if ((cmd == 't') || (cmd == '#')) {
10108
10109 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10110 res = 0;
10111 goto out;
10112 } else if (cmd < 0) {
10113
10114 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10115 res = -1;
10116 goto out;
10117 }
10118 }
10119 #ifdef IMAP_STORAGE
10120 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10121 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10122 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10123 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10124 }
10125 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10126 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10127 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10128 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10129 }
10130 #endif
10131
10132 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10133 if (play_auto) {
10134 cmd = '1';
10135 } else {
10136 cmd = vm_intro(chan, vmu, &vms);
10137 }
10138 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10139
10140 vms.repeats = 0;
10141 vms.starting = 1;
10142 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10143
10144 switch (cmd) {
10145 case '1':
10146 vms.curmsg = 0;
10147
10148 case '5':
10149 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10150 cmd = vm_browse_messages(chan, &vms, vmu);
10151 break;
10152 case '2':
10153 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10154 if (useadsi)
10155 adsi_folders(chan, 0, "Change to folder...");
10156
10157 cmd = get_folder2(chan, "vm-changeto", 0);
10158 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10159 if (cmd == '#') {
10160 cmd = 0;
10161 } else if (cmd > 0) {
10162 cmd = cmd - '0';
10163 res = close_mailbox(&vms, vmu);
10164 if (res == ERROR_LOCK_PATH)
10165 goto out;
10166
10167 if (cmd != 11) in_urgent = 0;
10168 res = open_mailbox(&vms, vmu, cmd);
10169 if (res < 0)
10170 goto out;
10171 play_folder = cmd;
10172 cmd = 0;
10173 }
10174 if (useadsi)
10175 adsi_status2(chan, &vms);
10176
10177 if (!cmd) {
10178 cmd = vm_play_folder_name(chan, vms.vmbox);
10179 }
10180
10181 vms.starting = 1;
10182 break;
10183 case '3':
10184 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10185 cmd = 0;
10186 vms.repeats = 0;
10187 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10188 switch (cmd) {
10189 case '1':
10190 if (vms.lastmsg > -1 && !vms.starting) {
10191 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10192 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10193 res = cmd;
10194 goto out;
10195 }
10196 } else {
10197 cmd = ast_play_and_wait(chan, "vm-sorry");
10198 }
10199 cmd = 't';
10200 break;
10201 case '2':
10202 if (!vms.starting)
10203 ast_verb(3, "Callback Requested\n");
10204 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10205 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10206 if (cmd == 9) {
10207 silentexit = 1;
10208 goto out;
10209 } else if (cmd == ERROR_LOCK_PATH) {
10210 res = cmd;
10211 goto out;
10212 }
10213 } else {
10214 cmd = ast_play_and_wait(chan, "vm-sorry");
10215 }
10216 cmd = 't';
10217 break;
10218 case '3':
10219 if (vms.lastmsg > -1 && !vms.starting) {
10220 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10221 if (cmd == ERROR_LOCK_PATH) {
10222 res = cmd;
10223 goto out;
10224 }
10225 } else {
10226 cmd = ast_play_and_wait(chan, "vm-sorry");
10227 }
10228 cmd = 't';
10229 break;
10230 case '4':
10231 if (!ast_strlen_zero(vmu->dialout)) {
10232 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10233 if (cmd == 9) {
10234 silentexit = 1;
10235 goto out;
10236 }
10237 } else {
10238 cmd = ast_play_and_wait(chan, "vm-sorry");
10239 }
10240 cmd = 't';
10241 break;
10242
10243 case '5':
10244 if (ast_test_flag(vmu, VM_SVMAIL)) {
10245 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10246 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10247 res = cmd;
10248 goto out;
10249 }
10250 } else {
10251 cmd = ast_play_and_wait(chan, "vm-sorry");
10252 }
10253 cmd = 't';
10254 break;
10255
10256 case '*':
10257 cmd = 't';
10258 break;
10259
10260 default:
10261 cmd = 0;
10262 if (!vms.starting) {
10263 cmd = ast_play_and_wait(chan, "vm-toreply");
10264 }
10265 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10266 cmd = ast_play_and_wait(chan, "vm-tocallback");
10267 }
10268 if (!cmd && !vms.starting) {
10269 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10270 }
10271 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10272 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10273 }
10274 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10275 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10276 }
10277 if (!cmd) {
10278 cmd = ast_play_and_wait(chan, "vm-starmain");
10279 }
10280 if (!cmd) {
10281 cmd = ast_waitfordigit(chan, 6000);
10282 }
10283 if (!cmd) {
10284 vms.repeats++;
10285 }
10286 if (vms.repeats > 3) {
10287 cmd = 't';
10288 }
10289 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10290 }
10291 }
10292 if (cmd == 't') {
10293 cmd = 0;
10294 vms.repeats = 0;
10295 }
10296 break;
10297 case '4':
10298 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10299 if (vms.curmsg > 0) {
10300 vms.curmsg--;
10301 cmd = play_message(chan, vmu, &vms);
10302 } else {
10303
10304
10305
10306
10307 if (in_urgent == 0 && vms.urgentmessages > 0) {
10308
10309 in_urgent = 1;
10310 res = close_mailbox(&vms, vmu);
10311 if (res == ERROR_LOCK_PATH)
10312 goto out;
10313 res = open_mailbox(&vms, vmu, 11);
10314 if (res < 0)
10315 goto out;
10316 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10317 vms.curmsg = vms.lastmsg;
10318 if (vms.lastmsg < 0) {
10319 cmd = ast_play_and_wait(chan, "vm-nomore");
10320 }
10321 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10322 vms.curmsg = vms.lastmsg;
10323 cmd = play_message(chan, vmu, &vms);
10324 } else {
10325 cmd = ast_play_and_wait(chan, "vm-nomore");
10326 }
10327 }
10328 break;
10329 case '6':
10330 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10331 if (vms.curmsg < vms.lastmsg) {
10332 vms.curmsg++;
10333 cmd = play_message(chan, vmu, &vms);
10334 } else {
10335 if (in_urgent && vms.newmessages > 0) {
10336
10337
10338
10339
10340 in_urgent = 0;
10341 res = close_mailbox(&vms, vmu);
10342 if (res == ERROR_LOCK_PATH)
10343 goto out;
10344 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10345 if (res < 0)
10346 goto out;
10347 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10348 vms.curmsg = -1;
10349 if (vms.lastmsg < 0) {
10350 cmd = ast_play_and_wait(chan, "vm-nomore");
10351 }
10352 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10353 vms.curmsg = 0;
10354 cmd = play_message(chan, vmu, &vms);
10355 } else {
10356 cmd = ast_play_and_wait(chan, "vm-nomore");
10357 }
10358 }
10359 break;
10360 case '7':
10361 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10362 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10363 if (useadsi)
10364 adsi_delete(chan, &vms);
10365 if (vms.deleted[vms.curmsg]) {
10366 if (play_folder == 0) {
10367 if (in_urgent) {
10368 vms.urgentmessages--;
10369 } else {
10370 vms.newmessages--;
10371 }
10372 }
10373 else if (play_folder == 1)
10374 vms.oldmessages--;
10375 cmd = ast_play_and_wait(chan, "vm-deleted");
10376 } else {
10377 if (play_folder == 0) {
10378 if (in_urgent) {
10379 vms.urgentmessages++;
10380 } else {
10381 vms.newmessages++;
10382 }
10383 }
10384 else if (play_folder == 1)
10385 vms.oldmessages++;
10386 cmd = ast_play_and_wait(chan, "vm-undeleted");
10387 }
10388 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10389 if (vms.curmsg < vms.lastmsg) {
10390 vms.curmsg++;
10391 cmd = play_message(chan, vmu, &vms);
10392 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10393 vms.curmsg = 0;
10394 cmd = play_message(chan, vmu, &vms);
10395 } else {
10396
10397
10398
10399
10400 if (in_urgent == 1) {
10401
10402 in_urgent = 0;
10403 res = close_mailbox(&vms, vmu);
10404 if (res == ERROR_LOCK_PATH)
10405 goto out;
10406 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10407 if (res < 0)
10408 goto out;
10409 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10410 vms.curmsg = -1;
10411 if (vms.lastmsg < 0) {
10412 cmd = ast_play_and_wait(chan, "vm-nomore");
10413 }
10414 } else {
10415 cmd = ast_play_and_wait(chan, "vm-nomore");
10416 }
10417 }
10418 }
10419 } else
10420 cmd = 0;
10421 #ifdef IMAP_STORAGE
10422 deleted = 1;
10423 #endif
10424 break;
10425
10426 case '8':
10427 if (vms.lastmsg > -1) {
10428 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10429 if (cmd == ERROR_LOCK_PATH) {
10430 res = cmd;
10431 goto out;
10432 }
10433 } else {
10434
10435
10436
10437
10438 if (in_urgent == 1 && vms.newmessages > 0) {
10439
10440 in_urgent = 0;
10441 res = close_mailbox(&vms, vmu);
10442 if (res == ERROR_LOCK_PATH)
10443 goto out;
10444 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10445 if (res < 0)
10446 goto out;
10447 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10448 vms.curmsg = -1;
10449 if (vms.lastmsg < 0) {
10450 cmd = ast_play_and_wait(chan, "vm-nomore");
10451 }
10452 } else {
10453 cmd = ast_play_and_wait(chan, "vm-nomore");
10454 }
10455 }
10456 break;
10457 case '9':
10458 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10459 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10460
10461 cmd = 0;
10462 break;
10463 }
10464 if (useadsi)
10465 adsi_folders(chan, 1, "Save to folder...");
10466 cmd = get_folder2(chan, "vm-savefolder", 1);
10467 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10468 box = 0;
10469 if (cmd == '#') {
10470 cmd = 0;
10471 break;
10472 } else if (cmd > 0) {
10473 box = cmd = cmd - '0';
10474 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10475 if (cmd == ERROR_LOCK_PATH) {
10476 res = cmd;
10477 goto out;
10478 #ifndef IMAP_STORAGE
10479 } else if (!cmd) {
10480 vms.deleted[vms.curmsg] = 1;
10481 #endif
10482 } else {
10483 vms.deleted[vms.curmsg] = 0;
10484 vms.heard[vms.curmsg] = 0;
10485 }
10486 }
10487 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10488 if (useadsi)
10489 adsi_message(chan, &vms);
10490 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10491 if (!cmd) {
10492 cmd = ast_play_and_wait(chan, "vm-message");
10493 if (!cmd)
10494 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10495 if (!cmd)
10496 cmd = ast_play_and_wait(chan, "vm-savedto");
10497 if (!cmd)
10498 cmd = vm_play_folder_name(chan, vms.fn);
10499 } else {
10500 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10501 }
10502 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10503 if (vms.curmsg < vms.lastmsg) {
10504 vms.curmsg++;
10505 cmd = play_message(chan, vmu, &vms);
10506 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10507 vms.curmsg = 0;
10508 cmd = play_message(chan, vmu, &vms);
10509 } else {
10510
10511
10512
10513
10514 if (in_urgent == 1 && vms.newmessages > 0) {
10515
10516 in_urgent = 0;
10517 res = close_mailbox(&vms, vmu);
10518 if (res == ERROR_LOCK_PATH)
10519 goto out;
10520 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10521 if (res < 0)
10522 goto out;
10523 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10524 vms.curmsg = -1;
10525 if (vms.lastmsg < 0) {
10526 cmd = ast_play_and_wait(chan, "vm-nomore");
10527 }
10528 } else {
10529 cmd = ast_play_and_wait(chan, "vm-nomore");
10530 }
10531 }
10532 }
10533 break;
10534 case '*':
10535 if (!vms.starting) {
10536 cmd = ast_play_and_wait(chan, "vm-onefor");
10537 if (!strncasecmp(chan->language, "he", 2)) {
10538 cmd = ast_play_and_wait(chan, "vm-for");
10539 }
10540 if (!cmd)
10541 cmd = vm_play_folder_name(chan, vms.vmbox);
10542 if (!cmd)
10543 cmd = ast_play_and_wait(chan, "vm-opts");
10544 if (!cmd)
10545 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10546 } else
10547 cmd = 0;
10548 break;
10549 case '0':
10550 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10551 if (useadsi)
10552 adsi_status(chan, &vms);
10553 break;
10554 default:
10555 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10556 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10557 break;
10558 }
10559 }
10560 if ((cmd == 't') || (cmd == '#')) {
10561
10562 res = 0;
10563 } else {
10564
10565 res = -1;
10566 }
10567
10568 out:
10569 if (res > -1) {
10570 ast_stopstream(chan);
10571 adsi_goodbye(chan);
10572 if (valid && res != OPERATOR_EXIT) {
10573 if (silentexit)
10574 res = ast_play_and_wait(chan, "vm-dialout");
10575 else
10576 res = ast_play_and_wait(chan, "vm-goodbye");
10577 }
10578 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10579 res = 0;
10580 }
10581 if (useadsi)
10582 ast_adsi_unload_session(chan);
10583 }
10584 if (vmu)
10585 close_mailbox(&vms, vmu);
10586 if (valid) {
10587 int new = 0, old = 0, urgent = 0;
10588 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10589 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10590
10591 run_externnotify(vmu->context, vmu->mailbox, NULL);
10592 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10593 queue_mwi_event(ext_context, urgent, new, old);
10594 }
10595 #ifdef IMAP_STORAGE
10596
10597 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10598 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10599 ast_mutex_lock(&vms.lock);
10600 #ifdef HAVE_IMAP_TK2006
10601 if (LEVELUIDPLUS (vms.mailstream)) {
10602 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10603 } else
10604 #endif
10605 mail_expunge(vms.mailstream);
10606 ast_mutex_unlock(&vms.lock);
10607 }
10608
10609
10610 if (vmu) {
10611 vmstate_delete(&vms);
10612 }
10613 #endif
10614 if (vmu)
10615 free_user(vmu);
10616 if (vms.deleted)
10617 ast_free(vms.deleted);
10618 if (vms.heard)
10619 ast_free(vms.heard);
10620
10621 #ifdef IMAP_STORAGE
10622 pthread_setspecific(ts_vmstate.key, NULL);
10623 #endif
10624 return res;
10625 }
10626
10627 static int vm_exec(struct ast_channel *chan, const char *data)
10628 {
10629 int res = 0;
10630 char *tmp;
10631 struct leave_vm_options leave_options;
10632 struct ast_flags flags = { 0 };
10633 char *opts[OPT_ARG_ARRAY_SIZE];
10634 AST_DECLARE_APP_ARGS(args,
10635 AST_APP_ARG(argv0);
10636 AST_APP_ARG(argv1);
10637 );
10638
10639 memset(&leave_options, 0, sizeof(leave_options));
10640
10641 if (chan->_state != AST_STATE_UP)
10642 ast_answer(chan);
10643
10644 if (!ast_strlen_zero(data)) {
10645 tmp = ast_strdupa(data);
10646 AST_STANDARD_APP_ARGS(args, tmp);
10647 if (args.argc == 2) {
10648 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10649 return -1;
10650 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10651 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10652 int gain;
10653
10654 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10655 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10656 return -1;
10657 } else {
10658 leave_options.record_gain = (signed char) gain;
10659 }
10660 }
10661 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10662 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10663 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10664 }
10665 }
10666 } else {
10667 char temp[256];
10668 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10669 if (res < 0)
10670 return res;
10671 if (ast_strlen_zero(temp))
10672 return 0;
10673 args.argv0 = ast_strdupa(temp);
10674 }
10675
10676 res = leave_voicemail(chan, args.argv0, &leave_options);
10677 if (res == 't') {
10678 ast_play_and_wait(chan, "vm-goodbye");
10679 res = 0;
10680 }
10681
10682 if (res == OPERATOR_EXIT) {
10683 res = 0;
10684 }
10685
10686 if (res == ERROR_LOCK_PATH) {
10687 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10688 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10689 res = 0;
10690 }
10691
10692 return res;
10693 }
10694
10695 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10696 {
10697 struct ast_vm_user *vmu;
10698
10699 if (!ast_strlen_zero(box) && box[0] == '*') {
10700 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10701 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10702 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10703 "\n\tand will be ignored.\n", box, context);
10704 return NULL;
10705 }
10706
10707 AST_LIST_TRAVERSE(&users, vmu, list) {
10708 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10709 if (strcasecmp(vmu->context, context)) {
10710 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10711 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10712 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10713 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10714 }
10715 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10716 return NULL;
10717 }
10718 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10719 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10720 return NULL;
10721 }
10722 }
10723
10724 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10725 return NULL;
10726
10727 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10728 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10729
10730 AST_LIST_INSERT_TAIL(&users, vmu, list);
10731
10732 return vmu;
10733 }
10734
10735 static int append_mailbox(const char *context, const char *box, const char *data)
10736 {
10737
10738 char *tmp;
10739 char *stringp;
10740 char *s;
10741 struct ast_vm_user *vmu;
10742 char *mailbox_full;
10743 int new = 0, old = 0, urgent = 0;
10744 char secretfn[PATH_MAX] = "";
10745
10746 tmp = ast_strdupa(data);
10747
10748 if (!(vmu = find_or_create(context, box)))
10749 return -1;
10750
10751 populate_defaults(vmu);
10752
10753 stringp = tmp;
10754 if ((s = strsep(&stringp, ","))) {
10755 if (!ast_strlen_zero(s) && s[0] == '*') {
10756 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10757 "\n\tmust be reset in voicemail.conf.\n", box);
10758 }
10759
10760 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10761 }
10762 if (stringp && (s = strsep(&stringp, ","))) {
10763 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10764 }
10765 if (stringp && (s = strsep(&stringp, ","))) {
10766 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10767 }
10768 if (stringp && (s = strsep(&stringp, ","))) {
10769 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10770 }
10771 if (stringp && (s = strsep(&stringp, ","))) {
10772 apply_options(vmu, s);
10773 }
10774
10775 switch (vmu->passwordlocation) {
10776 case OPT_PWLOC_SPOOLDIR:
10777 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10778 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10779 }
10780
10781 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10782 strcpy(mailbox_full, box);
10783 strcat(mailbox_full, "@");
10784 strcat(mailbox_full, context);
10785
10786 inboxcount2(mailbox_full, &urgent, &new, &old);
10787 queue_mwi_event(mailbox_full, urgent, new, old);
10788
10789 return 0;
10790 }
10791
10792 AST_TEST_DEFINE(test_voicemail_vmuser)
10793 {
10794 int res = 0;
10795 struct ast_vm_user *vmu;
10796
10797 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10798 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10799 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10800 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10801 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10802 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10803 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10804 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10805 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10806 #ifdef IMAP_STORAGE
10807 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10808 "imapfolder=INBOX|imapvmshareid=6000";
10809 #endif
10810
10811 switch (cmd) {
10812 case TEST_INIT:
10813 info->name = "vmuser";
10814 info->category = "/apps/app_voicemail/";
10815 info->summary = "Vmuser unit test";
10816 info->description =
10817 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10818 return AST_TEST_NOT_RUN;
10819 case TEST_EXECUTE:
10820 break;
10821 }
10822
10823 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10824 return AST_TEST_NOT_RUN;
10825 }
10826 ast_set_flag(vmu, VM_ALLOCED);
10827 populate_defaults(vmu);
10828
10829 apply_options(vmu, options_string);
10830
10831 if (!ast_test_flag(vmu, VM_ATTACH)) {
10832 ast_test_status_update(test, "Parse failure for attach option\n");
10833 res = 1;
10834 }
10835 if (strcasecmp(vmu->attachfmt, "wav49")) {
10836 ast_test_status_update(test, "Parse failure for attachftm option\n");
10837 res = 1;
10838 }
10839 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10840 ast_test_status_update(test, "Parse failure for serveremail option\n");
10841 res = 1;
10842 }
10843 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10844 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10845 res = 1;
10846 }
10847 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10848 ast_test_status_update(test, "Parse failure for emailbody option\n");
10849 res = 1;
10850 }
10851 if (strcasecmp(vmu->zonetag, "central")) {
10852 ast_test_status_update(test, "Parse failure for tz option\n");
10853 res = 1;
10854 }
10855 if (!ast_test_flag(vmu, VM_DELETE)) {
10856 ast_test_status_update(test, "Parse failure for delete option\n");
10857 res = 1;
10858 }
10859 if (!ast_test_flag(vmu, VM_SAYCID)) {
10860 ast_test_status_update(test, "Parse failure for saycid option\n");
10861 res = 1;
10862 }
10863 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10864 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10865 res = 1;
10866 }
10867 if (!ast_test_flag(vmu, VM_REVIEW)) {
10868 ast_test_status_update(test, "Parse failure for review option\n");
10869 res = 1;
10870 }
10871 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10872 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10873 res = 1;
10874 }
10875 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10876 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10877 res = 1;
10878 }
10879 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10880 ast_test_status_update(test, "Parse failure for operator option\n");
10881 res = 1;
10882 }
10883 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10884 ast_test_status_update(test, "Parse failure for envelope option\n");
10885 res = 1;
10886 }
10887 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10888 ast_test_status_update(test, "Parse failure for moveheard option\n");
10889 res = 1;
10890 }
10891 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10892 ast_test_status_update(test, "Parse failure for sayduration option\n");
10893 res = 1;
10894 }
10895 if (vmu->saydurationm != 5) {
10896 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10897 res = 1;
10898 }
10899 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10900 ast_test_status_update(test, "Parse failure for forcename option\n");
10901 res = 1;
10902 }
10903 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10904 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10905 res = 1;
10906 }
10907 if (strcasecmp(vmu->callback, "somecontext")) {
10908 ast_test_status_update(test, "Parse failure for callbacks option\n");
10909 res = 1;
10910 }
10911 if (strcasecmp(vmu->dialout, "somecontext2")) {
10912 ast_test_status_update(test, "Parse failure for dialout option\n");
10913 res = 1;
10914 }
10915 if (strcasecmp(vmu->exit, "somecontext3")) {
10916 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10917 res = 1;
10918 }
10919 if (vmu->minsecs != 10) {
10920 ast_test_status_update(test, "Parse failure for minsecs option\n");
10921 res = 1;
10922 }
10923 if (vmu->maxsecs != 100) {
10924 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10925 res = 1;
10926 }
10927 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10928 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10929 res = 1;
10930 }
10931 if (vmu->maxdeletedmsg != 50) {
10932 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10933 res = 1;
10934 }
10935 if (vmu->volgain != 1.3) {
10936 ast_test_status_update(test, "Parse failure for volgain option\n");
10937 res = 1;
10938 }
10939 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10940 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10941 res = 1;
10942 }
10943 #ifdef IMAP_STORAGE
10944 apply_options(vmu, option_string2);
10945
10946 if (strcasecmp(vmu->imapuser, "imapuser")) {
10947 ast_test_status_update(test, "Parse failure for imapuser option\n");
10948 res = 1;
10949 }
10950 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10951 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10952 res = 1;
10953 }
10954 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10955 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10956 res = 1;
10957 }
10958 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10959 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10960 res = 1;
10961 }
10962 #endif
10963
10964 free_user(vmu);
10965 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10966 }
10967
10968 static int vm_box_exists(struct ast_channel *chan, const char *data)
10969 {
10970 struct ast_vm_user svm;
10971 char *context, *box;
10972 AST_DECLARE_APP_ARGS(args,
10973 AST_APP_ARG(mbox);
10974 AST_APP_ARG(options);
10975 );
10976 static int dep_warning = 0;
10977
10978 if (ast_strlen_zero(data)) {
10979 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10980 return -1;
10981 }
10982
10983 if (!dep_warning) {
10984 dep_warning = 1;
10985 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10986 }
10987
10988 box = ast_strdupa(data);
10989
10990 AST_STANDARD_APP_ARGS(args, box);
10991
10992 if (args.options) {
10993 }
10994
10995 if ((context = strchr(args.mbox, '@'))) {
10996 *context = '\0';
10997 context++;
10998 }
10999
11000 if (find_user(&svm, context, args.mbox)) {
11001 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11002 } else
11003 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11004
11005 return 0;
11006 }
11007
11008 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11009 {
11010 struct ast_vm_user svm;
11011 AST_DECLARE_APP_ARGS(arg,
11012 AST_APP_ARG(mbox);
11013 AST_APP_ARG(context);
11014 );
11015
11016 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11017
11018 if (ast_strlen_zero(arg.mbox)) {
11019 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11020 return -1;
11021 }
11022
11023 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11024 return 0;
11025 }
11026
11027 static struct ast_custom_function mailbox_exists_acf = {
11028 .name = "MAILBOX_EXISTS",
11029 .read = acf_mailbox_exists,
11030 };
11031
11032 static int vmauthenticate(struct ast_channel *chan, const char *data)
11033 {
11034 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11035 struct ast_vm_user vmus;
11036 char *options = NULL;
11037 int silent = 0, skipuser = 0;
11038 int res = -1;
11039
11040 if (data) {
11041 s = ast_strdupa(data);
11042 user = strsep(&s, ",");
11043 options = strsep(&s, ",");
11044 if (user) {
11045 s = user;
11046 user = strsep(&s, "@");
11047 context = strsep(&s, "");
11048 if (!ast_strlen_zero(user))
11049 skipuser++;
11050 ast_copy_string(mailbox, user, sizeof(mailbox));
11051 }
11052 }
11053
11054 if (options) {
11055 silent = (strchr(options, 's')) != NULL;
11056 }
11057
11058 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11059 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11060 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11061 ast_play_and_wait(chan, "auth-thankyou");
11062 res = 0;
11063 } else if (mailbox[0] == '*') {
11064
11065 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11066 res = 0;
11067 }
11068 }
11069
11070 return res;
11071 }
11072
11073 static char *show_users_realtime(int fd, const char *context)
11074 {
11075 struct ast_config *cfg;
11076 const char *cat = NULL;
11077
11078 if (!(cfg = ast_load_realtime_multientry("voicemail",
11079 "context", context, SENTINEL))) {
11080 return CLI_FAILURE;
11081 }
11082
11083 ast_cli(fd,
11084 "\n"
11085 "=============================================================\n"
11086 "=== Configured Voicemail Users ==============================\n"
11087 "=============================================================\n"
11088 "===\n");
11089
11090 while ((cat = ast_category_browse(cfg, cat))) {
11091 struct ast_variable *var = NULL;
11092 ast_cli(fd,
11093 "=== Mailbox ...\n"
11094 "===\n");
11095 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11096 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11097 ast_cli(fd,
11098 "===\n"
11099 "=== ---------------------------------------------------------\n"
11100 "===\n");
11101 }
11102
11103 ast_cli(fd,
11104 "=============================================================\n"
11105 "\n");
11106
11107 ast_config_destroy(cfg);
11108
11109 return CLI_SUCCESS;
11110 }
11111
11112 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11113 {
11114 int which = 0;
11115 int wordlen;
11116 struct ast_vm_user *vmu;
11117 const char *context = "";
11118
11119
11120 if (pos > 4)
11121 return NULL;
11122 if (pos == 3)
11123 return (state == 0) ? ast_strdup("for") : NULL;
11124 wordlen = strlen(word);
11125 AST_LIST_TRAVERSE(&users, vmu, list) {
11126 if (!strncasecmp(word, vmu->context, wordlen)) {
11127 if (context && strcmp(context, vmu->context) && ++which > state)
11128 return ast_strdup(vmu->context);
11129
11130 context = vmu->context;
11131 }
11132 }
11133 return NULL;
11134 }
11135
11136
11137 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11138 {
11139 struct ast_vm_user *vmu;
11140 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11141 const char *context = NULL;
11142 int users_counter = 0;
11143
11144 switch (cmd) {
11145 case CLI_INIT:
11146 e->command = "voicemail show users";
11147 e->usage =
11148 "Usage: voicemail show users [for <context>]\n"
11149 " Lists all mailboxes currently set up\n";
11150 return NULL;
11151 case CLI_GENERATE:
11152 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11153 }
11154
11155 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11156 return CLI_SHOWUSAGE;
11157 if (a->argc == 5) {
11158 if (strcmp(a->argv[3],"for"))
11159 return CLI_SHOWUSAGE;
11160 context = a->argv[4];
11161 }
11162
11163 if (ast_check_realtime("voicemail")) {
11164 if (!context) {
11165 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11166 return CLI_SHOWUSAGE;
11167 }
11168 return show_users_realtime(a->fd, context);
11169 }
11170
11171 AST_LIST_LOCK(&users);
11172 if (AST_LIST_EMPTY(&users)) {
11173 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11174 AST_LIST_UNLOCK(&users);
11175 return CLI_FAILURE;
11176 }
11177 if (a->argc == 3)
11178 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11179 else {
11180 int count = 0;
11181 AST_LIST_TRAVERSE(&users, vmu, list) {
11182 if (!strcmp(context, vmu->context))
11183 count++;
11184 }
11185 if (count) {
11186 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11187 } else {
11188 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11189 AST_LIST_UNLOCK(&users);
11190 return CLI_FAILURE;
11191 }
11192 }
11193 AST_LIST_TRAVERSE(&users, vmu, list) {
11194 int newmsgs = 0, oldmsgs = 0;
11195 char count[12], tmp[256] = "";
11196
11197 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
11198 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11199 inboxcount(tmp, &newmsgs, &oldmsgs);
11200 snprintf(count, sizeof(count), "%d", newmsgs);
11201 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11202 users_counter++;
11203 }
11204 }
11205 AST_LIST_UNLOCK(&users);
11206 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11207 return CLI_SUCCESS;
11208 }
11209
11210
11211 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11212 {
11213 struct vm_zone *zone;
11214 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11215 char *res = CLI_SUCCESS;
11216
11217 switch (cmd) {
11218 case CLI_INIT:
11219 e->command = "voicemail show zones";
11220 e->usage =
11221 "Usage: voicemail show zones\n"
11222 " Lists zone message formats\n";
11223 return NULL;
11224 case CLI_GENERATE:
11225 return NULL;
11226 }
11227
11228 if (a->argc != 3)
11229 return CLI_SHOWUSAGE;
11230
11231 AST_LIST_LOCK(&zones);
11232 if (!AST_LIST_EMPTY(&zones)) {
11233 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11234 AST_LIST_TRAVERSE(&zones, zone, list) {
11235 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11236 }
11237 } else {
11238 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11239 res = CLI_FAILURE;
11240 }
11241 AST_LIST_UNLOCK(&zones);
11242
11243 return res;
11244 }
11245
11246
11247 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11248 {
11249 switch (cmd) {
11250 case CLI_INIT:
11251 e->command = "voicemail reload";
11252 e->usage =
11253 "Usage: voicemail reload\n"
11254 " Reload voicemail configuration\n";
11255 return NULL;
11256 case CLI_GENERATE:
11257 return NULL;
11258 }
11259
11260 if (a->argc != 2)
11261 return CLI_SHOWUSAGE;
11262
11263 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11264 load_config(1);
11265
11266 return CLI_SUCCESS;
11267 }
11268
11269 static struct ast_cli_entry cli_voicemail[] = {
11270 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11271 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11272 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11273 };
11274
11275 #ifdef IMAP_STORAGE
11276 #define DATA_EXPORT_VM_USERS(USER) \
11277 USER(ast_vm_user, context, AST_DATA_STRING) \
11278 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11279 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11280 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11281 USER(ast_vm_user, email, AST_DATA_STRING) \
11282 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11283 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11284 USER(ast_vm_user, pager, AST_DATA_STRING) \
11285 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11286 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11287 USER(ast_vm_user, language, AST_DATA_STRING) \
11288 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11289 USER(ast_vm_user, callback, AST_DATA_STRING) \
11290 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11291 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11292 USER(ast_vm_user, exit, AST_DATA_STRING) \
11293 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11294 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11295 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11296 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11297 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11298 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11299 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11300 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11301 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11302 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11303 #else
11304 #define DATA_EXPORT_VM_USERS(USER) \
11305 USER(ast_vm_user, context, AST_DATA_STRING) \
11306 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11307 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11308 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11309 USER(ast_vm_user, email, AST_DATA_STRING) \
11310 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11311 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11312 USER(ast_vm_user, pager, AST_DATA_STRING) \
11313 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11314 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11315 USER(ast_vm_user, language, AST_DATA_STRING) \
11316 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11317 USER(ast_vm_user, callback, AST_DATA_STRING) \
11318 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11319 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11320 USER(ast_vm_user, exit, AST_DATA_STRING) \
11321 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11322 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11323 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11324 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11325 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11326 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11327 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11328 #endif
11329
11330 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11331
11332 #define DATA_EXPORT_VM_ZONES(ZONE) \
11333 ZONE(vm_zone, name, AST_DATA_STRING) \
11334 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11335 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11336
11337 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11338
11339
11340
11341
11342
11343
11344
11345
11346 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11347 struct ast_data *data_root, struct ast_vm_user *user)
11348 {
11349 struct ast_data *data_user, *data_zone;
11350 struct ast_data *data_state;
11351 struct vm_zone *zone = NULL;
11352 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11353 char ext_context[256] = "";
11354
11355 data_user = ast_data_add_node(data_root, "user");
11356 if (!data_user) {
11357 return -1;
11358 }
11359
11360 ast_data_add_structure(ast_vm_user, data_user, user);
11361
11362 AST_LIST_LOCK(&zones);
11363 AST_LIST_TRAVERSE(&zones, zone, list) {
11364 if (!strcmp(zone->name, user->zonetag)) {
11365 break;
11366 }
11367 }
11368 AST_LIST_UNLOCK(&zones);
11369
11370
11371 data_state = ast_data_add_node(data_user, "state");
11372 if (!data_state) {
11373 return -1;
11374 }
11375 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11376 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11377 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11378 ast_data_add_int(data_state, "newmsg", newmsg);
11379 ast_data_add_int(data_state, "oldmsg", oldmsg);
11380
11381 if (zone) {
11382 data_zone = ast_data_add_node(data_user, "zone");
11383 ast_data_add_structure(vm_zone, data_zone, zone);
11384 }
11385
11386 if (!ast_data_search_match(search, data_user)) {
11387 ast_data_remove_node(data_root, data_user);
11388 }
11389
11390 return 0;
11391 }
11392
11393 static int vm_users_data_provider_get(const struct ast_data_search *search,
11394 struct ast_data *data_root)
11395 {
11396 struct ast_vm_user *user;
11397
11398 AST_LIST_LOCK(&users);
11399 AST_LIST_TRAVERSE(&users, user, list) {
11400 vm_users_data_provider_get_helper(search, data_root, user);
11401 }
11402 AST_LIST_UNLOCK(&users);
11403
11404 return 0;
11405 }
11406
11407 static const struct ast_data_handler vm_users_data_provider = {
11408 .version = AST_DATA_HANDLER_VERSION,
11409 .get = vm_users_data_provider_get
11410 };
11411
11412 static const struct ast_data_entry vm_data_providers[] = {
11413 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11414 };
11415
11416 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11417 {
11418 int new = 0, old = 0, urgent = 0;
11419
11420 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11421
11422 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11423 mwi_sub->old_urgent = urgent;
11424 mwi_sub->old_new = new;
11425 mwi_sub->old_old = old;
11426 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11427 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11428 }
11429 }
11430
11431 static void poll_subscribed_mailboxes(void)
11432 {
11433 struct mwi_sub *mwi_sub;
11434
11435 AST_RWLIST_RDLOCK(&mwi_subs);
11436 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11437 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11438 poll_subscribed_mailbox(mwi_sub);
11439 }
11440 }
11441 AST_RWLIST_UNLOCK(&mwi_subs);
11442 }
11443
11444 static void *mb_poll_thread(void *data)
11445 {
11446 while (poll_thread_run) {
11447 struct timespec ts = { 0, };
11448 struct timeval wait;
11449
11450 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11451 ts.tv_sec = wait.tv_sec;
11452 ts.tv_nsec = wait.tv_usec * 1000;
11453
11454 ast_mutex_lock(&poll_lock);
11455 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11456 ast_mutex_unlock(&poll_lock);
11457
11458 if (!poll_thread_run)
11459 break;
11460
11461 poll_subscribed_mailboxes();
11462 }
11463
11464 return NULL;
11465 }
11466
11467 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11468 {
11469 ast_free(mwi_sub);
11470 }
11471
11472 static int handle_unsubscribe(void *datap)
11473 {
11474 struct mwi_sub *mwi_sub;
11475 uint32_t *uniqueid = datap;
11476
11477 AST_RWLIST_WRLOCK(&mwi_subs);
11478 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11479 if (mwi_sub->uniqueid == *uniqueid) {
11480 AST_LIST_REMOVE_CURRENT(entry);
11481 break;
11482 }
11483 }
11484 AST_RWLIST_TRAVERSE_SAFE_END
11485 AST_RWLIST_UNLOCK(&mwi_subs);
11486
11487 if (mwi_sub)
11488 mwi_sub_destroy(mwi_sub);
11489
11490 ast_free(uniqueid);
11491 return 0;
11492 }
11493
11494 static int handle_subscribe(void *datap)
11495 {
11496 unsigned int len;
11497 struct mwi_sub *mwi_sub;
11498 struct mwi_sub_task *p = datap;
11499
11500 len = sizeof(*mwi_sub);
11501 if (!ast_strlen_zero(p->mailbox))
11502 len += strlen(p->mailbox);
11503
11504 if (!ast_strlen_zero(p->context))
11505 len += strlen(p->context) + 1;
11506
11507 if (!(mwi_sub = ast_calloc(1, len)))
11508 return -1;
11509
11510 mwi_sub->uniqueid = p->uniqueid;
11511 if (!ast_strlen_zero(p->mailbox))
11512 strcpy(mwi_sub->mailbox, p->mailbox);
11513
11514 if (!ast_strlen_zero(p->context)) {
11515 strcat(mwi_sub->mailbox, "@");
11516 strcat(mwi_sub->mailbox, p->context);
11517 }
11518
11519 AST_RWLIST_WRLOCK(&mwi_subs);
11520 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11521 AST_RWLIST_UNLOCK(&mwi_subs);
11522 ast_free((void *) p->mailbox);
11523 ast_free((void *) p->context);
11524 ast_free(p);
11525 poll_subscribed_mailbox(mwi_sub);
11526 return 0;
11527 }
11528
11529 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11530 {
11531 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11532 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
11533 return;
11534
11535 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11536 return;
11537
11538 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11539 *uniqueid = u;
11540 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11541 ast_free(uniqueid);
11542 }
11543 }
11544
11545 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11546 {
11547 struct mwi_sub_task *mwist;
11548
11549 if (ast_event_get_type(event) != AST_EVENT_SUB)
11550 return;
11551
11552 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11553 return;
11554
11555 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11556 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11557 return;
11558 }
11559 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11560 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11561 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11562
11563 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11564 ast_free(mwist);
11565 }
11566 }
11567
11568 static void start_poll_thread(void)
11569 {
11570 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11571 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11572 AST_EVENT_IE_END);
11573
11574 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11575 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11576 AST_EVENT_IE_END);
11577
11578 if (mwi_sub_sub)
11579 ast_event_report_subs(mwi_sub_sub);
11580
11581 poll_thread_run = 1;
11582
11583 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
11584 }
11585
11586 static void stop_poll_thread(void)
11587 {
11588 poll_thread_run = 0;
11589
11590 if (mwi_sub_sub) {
11591 ast_event_unsubscribe(mwi_sub_sub);
11592 mwi_sub_sub = NULL;
11593 }
11594
11595 if (mwi_unsub_sub) {
11596 ast_event_unsubscribe(mwi_unsub_sub);
11597 mwi_unsub_sub = NULL;
11598 }
11599
11600 ast_mutex_lock(&poll_lock);
11601 ast_cond_signal(&poll_cond);
11602 ast_mutex_unlock(&poll_lock);
11603
11604 pthread_join(poll_thread, NULL);
11605
11606 poll_thread = AST_PTHREADT_NULL;
11607 }
11608
11609
11610 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11611 {
11612 struct ast_vm_user *vmu = NULL;
11613 const char *id = astman_get_header(m, "ActionID");
11614 char actionid[128] = "";
11615
11616 if (!ast_strlen_zero(id))
11617 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11618
11619 AST_LIST_LOCK(&users);
11620
11621 if (AST_LIST_EMPTY(&users)) {
11622 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11623 AST_LIST_UNLOCK(&users);
11624 return RESULT_SUCCESS;
11625 }
11626
11627 astman_send_ack(s, m, "Voicemail user list will follow");
11628
11629 AST_LIST_TRAVERSE(&users, vmu, list) {
11630 char dirname[256];
11631
11632 #ifdef IMAP_STORAGE
11633 int new, old;
11634 inboxcount(vmu->mailbox, &new, &old);
11635 #endif
11636
11637 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11638 astman_append(s,
11639 "%s"
11640 "Event: VoicemailUserEntry\r\n"
11641 "VMContext: %s\r\n"
11642 "VoiceMailbox: %s\r\n"
11643 "Fullname: %s\r\n"
11644 "Email: %s\r\n"
11645 "Pager: %s\r\n"
11646 "ServerEmail: %s\r\n"
11647 "MailCommand: %s\r\n"
11648 "Language: %s\r\n"
11649 "TimeZone: %s\r\n"
11650 "Callback: %s\r\n"
11651 "Dialout: %s\r\n"
11652 "UniqueID: %s\r\n"
11653 "ExitContext: %s\r\n"
11654 "SayDurationMinimum: %d\r\n"
11655 "SayEnvelope: %s\r\n"
11656 "SayCID: %s\r\n"
11657 "AttachMessage: %s\r\n"
11658 "AttachmentFormat: %s\r\n"
11659 "DeleteMessage: %s\r\n"
11660 "VolumeGain: %.2f\r\n"
11661 "CanReview: %s\r\n"
11662 "CallOperator: %s\r\n"
11663 "MaxMessageCount: %d\r\n"
11664 "MaxMessageLength: %d\r\n"
11665 "NewMessageCount: %d\r\n"
11666 #ifdef IMAP_STORAGE
11667 "OldMessageCount: %d\r\n"
11668 "IMAPUser: %s\r\n"
11669 #endif
11670 "\r\n",
11671 actionid,
11672 vmu->context,
11673 vmu->mailbox,
11674 vmu->fullname,
11675 vmu->email,
11676 vmu->pager,
11677 vmu->serveremail,
11678 vmu->mailcmd,
11679 vmu->language,
11680 vmu->zonetag,
11681 vmu->callback,
11682 vmu->dialout,
11683 vmu->uniqueid,
11684 vmu->exit,
11685 vmu->saydurationm,
11686 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11687 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11688 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11689 vmu->attachfmt,
11690 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11691 vmu->volgain,
11692 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11693 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11694 vmu->maxmsg,
11695 vmu->maxsecs,
11696 #ifdef IMAP_STORAGE
11697 new, old, vmu->imapuser
11698 #else
11699 count_messages(vmu, dirname)
11700 #endif
11701 );
11702 }
11703 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11704
11705 AST_LIST_UNLOCK(&users);
11706
11707 return RESULT_SUCCESS;
11708 }
11709
11710
11711 static void free_vm_users(void)
11712 {
11713 struct ast_vm_user *current;
11714 AST_LIST_LOCK(&users);
11715 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11716 ast_set_flag(current, VM_ALLOCED);
11717 free_user(current);
11718 }
11719 AST_LIST_UNLOCK(&users);
11720 }
11721
11722
11723 static void free_vm_zones(void)
11724 {
11725 struct vm_zone *zcur;
11726 AST_LIST_LOCK(&zones);
11727 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11728 free_zone(zcur);
11729 AST_LIST_UNLOCK(&zones);
11730 }
11731
11732 static const char *substitute_escapes(const char *value)
11733 {
11734 char *current;
11735
11736
11737 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11738
11739 ast_str_reset(str);
11740
11741
11742 for (current = (char *) value; *current; current++) {
11743 if (*current == '\\') {
11744 current++;
11745 if (!*current) {
11746 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11747 break;
11748 }
11749 switch (*current) {
11750 case '\\':
11751 ast_str_append(&str, 0, "\\");
11752 break;
11753 case 'r':
11754 ast_str_append(&str, 0, "\r");
11755 break;
11756 case 'n':
11757 #ifdef IMAP_STORAGE
11758 if (!str->used || str->str[str->used - 1] != '\r') {
11759 ast_str_append(&str, 0, "\r");
11760 }
11761 #endif
11762 ast_str_append(&str, 0, "\n");
11763 break;
11764 case 't':
11765 ast_str_append(&str, 0, "\t");
11766 break;
11767 default:
11768 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11769 break;
11770 }
11771 } else {
11772 ast_str_append(&str, 0, "%c", *current);
11773 }
11774 }
11775
11776 return ast_str_buffer(str);
11777 }
11778
11779 static int load_config(int reload)
11780 {
11781 struct ast_config *cfg, *ucfg;
11782 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11783 int res;
11784
11785 ast_unload_realtime("voicemail");
11786 ast_unload_realtime("voicemail_data");
11787
11788 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11789 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11790 return 0;
11791 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11792 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11793 ucfg = NULL;
11794 }
11795 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11796 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11797 ast_config_destroy(ucfg);
11798 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11799 return 0;
11800 }
11801 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11802 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11803 return 0;
11804 } else {
11805 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11806 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11807 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11808 ucfg = NULL;
11809 }
11810 }
11811
11812 res = actual_load_config(reload, cfg, ucfg);
11813
11814 ast_config_destroy(cfg);
11815 ast_config_destroy(ucfg);
11816
11817 return res;
11818 }
11819
11820 #ifdef TEST_FRAMEWORK
11821 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11822 {
11823 ast_unload_realtime("voicemail");
11824 ast_unload_realtime("voicemail_data");
11825 return actual_load_config(reload, cfg, ucfg);
11826 }
11827 #endif
11828
11829 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11830 {
11831 struct ast_vm_user *current;
11832 char *cat;
11833 struct ast_variable *var;
11834 const char *val;
11835 char *q, *stringp, *tmp;
11836 int x;
11837 int tmpadsi[4];
11838 char secretfn[PATH_MAX] = "";
11839
11840 #ifdef IMAP_STORAGE
11841 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11842 #endif
11843
11844 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11845 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11846 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11847 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11848 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11849
11850
11851 free_vm_users();
11852
11853
11854 free_vm_zones();
11855
11856 AST_LIST_LOCK(&users);
11857
11858 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11859 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11860
11861 if (cfg) {
11862
11863
11864 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11865 val = "default";
11866 ast_copy_string(userscontext, val, sizeof(userscontext));
11867
11868 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11869 val = "yes";
11870 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11871
11872 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11873 val = "no";
11874 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11875
11876 volgain = 0.0;
11877 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11878 sscanf(val, "%30lf", &volgain);
11879
11880 #ifdef ODBC_STORAGE
11881 strcpy(odbc_database, "asterisk");
11882 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11883 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11884 }
11885 strcpy(odbc_table, "voicemessages");
11886 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11887 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11888 }
11889 #endif
11890
11891 strcpy(mailcmd, SENDMAIL);
11892 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11893 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11894
11895 maxsilence = 0;
11896 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11897 maxsilence = atoi(val);
11898 if (maxsilence > 0)
11899 maxsilence *= 1000;
11900 }
11901
11902 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11903 maxmsg = MAXMSG;
11904 } else {
11905 maxmsg = atoi(val);
11906 if (maxmsg < 0) {
11907 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11908 maxmsg = MAXMSG;
11909 } else if (maxmsg > MAXMSGLIMIT) {
11910 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11911 maxmsg = MAXMSGLIMIT;
11912 }
11913 }
11914
11915 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11916 maxdeletedmsg = 0;
11917 } else {
11918 if (sscanf(val, "%30d", &x) == 1)
11919 maxdeletedmsg = x;
11920 else if (ast_true(val))
11921 maxdeletedmsg = MAXMSG;
11922 else
11923 maxdeletedmsg = 0;
11924
11925 if (maxdeletedmsg < 0) {
11926 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11927 maxdeletedmsg = MAXMSG;
11928 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11929 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11930 maxdeletedmsg = MAXMSGLIMIT;
11931 }
11932 }
11933
11934
11935 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11936 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11937 }
11938
11939
11940 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11941 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11942 }
11943
11944
11945 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11946 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11947 pwdchange = PWDCHANGE_EXTERNAL;
11948 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11949 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11950 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11951 }
11952
11953
11954 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11955 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11956 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11957 }
11958
11959 #ifdef IMAP_STORAGE
11960
11961 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11962 ast_copy_string(imapserver, val, sizeof(imapserver));
11963 } else {
11964 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11965 }
11966
11967 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11968 ast_copy_string(imapport, val, sizeof(imapport));
11969 } else {
11970 ast_copy_string(imapport, "143", sizeof(imapport));
11971 }
11972
11973 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11974 ast_copy_string(imapflags, val, sizeof(imapflags));
11975 }
11976
11977 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11978 ast_copy_string(authuser, val, sizeof(authuser));
11979 }
11980
11981 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11982 ast_copy_string(authpassword, val, sizeof(authpassword));
11983 }
11984
11985 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11986 if (ast_false(val))
11987 expungeonhangup = 0;
11988 else
11989 expungeonhangup = 1;
11990 } else {
11991 expungeonhangup = 1;
11992 }
11993
11994 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
11995 ast_copy_string(imapfolder, val, sizeof(imapfolder));
11996 } else {
11997 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
11998 }
11999 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12000 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12001 }
12002 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12003 imapgreetings = ast_true(val);
12004 } else {
12005 imapgreetings = 0;
12006 }
12007 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12008 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12009 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12010
12011 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12012 } else {
12013 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12014 }
12015
12016
12017
12018
12019
12020 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12021 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12022 } else {
12023 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12024 }
12025
12026 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12027 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12028 } else {
12029 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12030 }
12031
12032 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12033 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12034 } else {
12035 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12036 }
12037
12038 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12039 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12040 } else {
12041 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12042 }
12043
12044
12045 imapversion++;
12046 #endif
12047
12048 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12049 ast_copy_string(externnotify, val, sizeof(externnotify));
12050 ast_debug(1, "found externnotify: %s\n", externnotify);
12051 } else {
12052 externnotify[0] = '\0';
12053 }
12054
12055
12056 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12057 ast_debug(1, "Enabled SMDI voicemail notification\n");
12058 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12059 smdi_iface = ast_smdi_interface_find(val);
12060 } else {
12061 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12062 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12063 }
12064 if (!smdi_iface) {
12065 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12066 }
12067 }
12068
12069
12070 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12071 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12072 silencethreshold = atoi(val);
12073
12074 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12075 val = ASTERISK_USERNAME;
12076 ast_copy_string(serveremail, val, sizeof(serveremail));
12077
12078 vmmaxsecs = 0;
12079 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12080 if (sscanf(val, "%30d", &x) == 1) {
12081 vmmaxsecs = x;
12082 } else {
12083 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12084 }
12085 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12086 static int maxmessage_deprecate = 0;
12087 if (maxmessage_deprecate == 0) {
12088 maxmessage_deprecate = 1;
12089 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12090 }
12091 if (sscanf(val, "%30d", &x) == 1) {
12092 vmmaxsecs = x;
12093 } else {
12094 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12095 }
12096 }
12097
12098 vmminsecs = 0;
12099 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
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 minsecs or you may get empty messages\n");
12104 }
12105 } else {
12106 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12107 }
12108 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12109 static int maxmessage_deprecate = 0;
12110 if (maxmessage_deprecate == 0) {
12111 maxmessage_deprecate = 1;
12112 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12113 }
12114 if (sscanf(val, "%30d", &x) == 1) {
12115 vmminsecs = x;
12116 if (maxsilence / 1000 >= vmminsecs) {
12117 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12118 }
12119 } else {
12120 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12121 }
12122 }
12123
12124 val = ast_variable_retrieve(cfg, "general", "format");
12125 if (!val) {
12126 val = "wav";
12127 } else {
12128 tmp = ast_strdupa(val);
12129 val = ast_format_str_reduce(tmp);
12130 if (!val) {
12131 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12132 val = "wav";
12133 }
12134 }
12135 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12136
12137 skipms = 3000;
12138 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12139 if (sscanf(val, "%30d", &x) == 1) {
12140 maxgreet = x;
12141 } else {
12142 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12143 }
12144 }
12145
12146 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12147 if (sscanf(val, "%30d", &x) == 1) {
12148 skipms = x;
12149 } else {
12150 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12151 }
12152 }
12153
12154 maxlogins = 3;
12155 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12156 if (sscanf(val, "%30d", &x) == 1) {
12157 maxlogins = x;
12158 } else {
12159 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12160 }
12161 }
12162
12163 minpassword = MINPASSWORD;
12164 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12165 if (sscanf(val, "%30d", &x) == 1) {
12166 minpassword = x;
12167 } else {
12168 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12169 }
12170 }
12171
12172
12173 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12174 val = "no";
12175 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12176
12177
12178 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12179 val = "no";
12180 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12181
12182 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12183 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12184 stringp = ast_strdupa(val);
12185 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12186 if (!ast_strlen_zero(stringp)) {
12187 q = strsep(&stringp, ",");
12188 while ((*q == ' ')||(*q == '\t'))
12189 q++;
12190 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12191 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12192 } else {
12193 cidinternalcontexts[x][0] = '\0';
12194 }
12195 }
12196 }
12197 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12198 ast_debug(1, "VM Review Option disabled globally\n");
12199 val = "no";
12200 }
12201 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12202
12203
12204 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12205 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12206 val = "no";
12207 } else {
12208 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12209 }
12210 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12211 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12212 ast_debug(1, "VM next message wrap disabled globally\n");
12213 val = "no";
12214 }
12215 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12216
12217 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12218 ast_debug(1, "VM Operator break disabled globally\n");
12219 val = "no";
12220 }
12221 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12222
12223 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12224 ast_debug(1, "VM CID Info before msg disabled globally\n");
12225 val = "no";
12226 }
12227 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12228
12229 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12230 ast_debug(1, "Send Voicemail msg disabled globally\n");
12231 val = "no";
12232 }
12233 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12234
12235 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12236 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12237 val = "yes";
12238 }
12239 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12240
12241 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12242 ast_debug(1, "Move Heard enabled globally\n");
12243 val = "yes";
12244 }
12245 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12246
12247 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12248 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12249 val = "no";
12250 }
12251 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12252
12253 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12254 ast_debug(1, "Duration info before msg enabled globally\n");
12255 val = "yes";
12256 }
12257 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12258
12259 saydurationminfo = 2;
12260 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12261 if (sscanf(val, "%30d", &x) == 1) {
12262 saydurationminfo = x;
12263 } else {
12264 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12265 }
12266 }
12267
12268 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12269 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12270 val = "no";
12271 }
12272 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12273
12274 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12275 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12276 ast_debug(1, "found dialout context: %s\n", dialcontext);
12277 } else {
12278 dialcontext[0] = '\0';
12279 }
12280
12281 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12282 ast_copy_string(callcontext, val, sizeof(callcontext));
12283 ast_debug(1, "found callback context: %s\n", callcontext);
12284 } else {
12285 callcontext[0] = '\0';
12286 }
12287
12288 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12289 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12290 ast_debug(1, "found operator context: %s\n", exitcontext);
12291 } else {
12292 exitcontext[0] = '\0';
12293 }
12294
12295
12296 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12297 ast_copy_string(vm_password, val, sizeof(vm_password));
12298 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12299 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12300 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12301 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12302 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12303 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12304 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12305 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12306 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12307 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12308 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12309 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12310 }
12311 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12312 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12313 }
12314
12315 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12316 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12317 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12318 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12319 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12320 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12321 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12322 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12323 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12324 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12325
12326 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12327 val = "no";
12328 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12329
12330 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12331 val = "voicemail.conf";
12332 }
12333 if (!(strcmp(val, "spooldir"))) {
12334 passwordlocation = OPT_PWLOC_SPOOLDIR;
12335 } else {
12336 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12337 }
12338
12339 poll_freq = DEFAULT_POLL_FREQ;
12340 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12341 if (sscanf(val, "%30u", &poll_freq) != 1) {
12342 poll_freq = DEFAULT_POLL_FREQ;
12343 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12344 }
12345 }
12346
12347 poll_mailboxes = 0;
12348 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12349 poll_mailboxes = ast_true(val);
12350
12351 memset(fromstring, 0, sizeof(fromstring));
12352 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12353 strcpy(charset, "ISO-8859-1");
12354 if (emailbody) {
12355 ast_free(emailbody);
12356 emailbody = NULL;
12357 }
12358 if (emailsubject) {
12359 ast_free(emailsubject);
12360 emailsubject = NULL;
12361 }
12362 if (pagerbody) {
12363 ast_free(pagerbody);
12364 pagerbody = NULL;
12365 }
12366 if (pagersubject) {
12367 ast_free(pagersubject);
12368 pagersubject = NULL;
12369 }
12370 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12371 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12372 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12373 ast_copy_string(fromstring, val, sizeof(fromstring));
12374 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12375 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12376 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12377 ast_copy_string(charset, val, sizeof(charset));
12378 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12379 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12380 for (x = 0; x < 4; x++) {
12381 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12382 }
12383 }
12384 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12385 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12386 for (x = 0; x < 4; x++) {
12387 memcpy(&adsisec[x], &tmpadsi[x], 1);
12388 }
12389 }
12390 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12391 if (atoi(val)) {
12392 adsiver = atoi(val);
12393 }
12394 }
12395 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12396 ast_copy_string(zonetag, val, sizeof(zonetag));
12397 }
12398 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12399 ast_copy_string(locale, val, sizeof(locale));
12400 }
12401 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12402 emailsubject = ast_strdup(substitute_escapes(val));
12403 }
12404 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12405 emailbody = ast_strdup(substitute_escapes(val));
12406 }
12407 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12408 pagersubject = ast_strdup(substitute_escapes(val));
12409 }
12410 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12411 pagerbody = ast_strdup(substitute_escapes(val));
12412 }
12413
12414
12415 if (ucfg) {
12416 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12417 if (!strcasecmp(cat, "general")) {
12418 continue;
12419 }
12420 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12421 continue;
12422 if ((current = find_or_create(userscontext, cat))) {
12423 populate_defaults(current);
12424 apply_options_full(current, ast_variable_browse(ucfg, cat));
12425 ast_copy_string(current->context, userscontext, sizeof(current->context));
12426 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12427 current->passwordlocation = OPT_PWLOC_USERSCONF;
12428 }
12429
12430 switch (current->passwordlocation) {
12431 case OPT_PWLOC_SPOOLDIR:
12432 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12433 read_password_from_file(secretfn, current->password, sizeof(current->password));
12434 }
12435 }
12436 }
12437 }
12438
12439
12440 cat = ast_category_browse(cfg, NULL);
12441 while (cat) {
12442 if (strcasecmp(cat, "general")) {
12443 var = ast_variable_browse(cfg, cat);
12444 if (strcasecmp(cat, "zonemessages")) {
12445
12446 while (var) {
12447 append_mailbox(cat, var->name, var->value);
12448 var = var->next;
12449 }
12450 } else {
12451
12452 while (var) {
12453 struct vm_zone *z;
12454 if ((z = ast_malloc(sizeof(*z)))) {
12455 char *msg_format, *tzone;
12456 msg_format = ast_strdupa(var->value);
12457 tzone = strsep(&msg_format, "|,");
12458 if (msg_format) {
12459 ast_copy_string(z->name, var->name, sizeof(z->name));
12460 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12461 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12462 AST_LIST_LOCK(&zones);
12463 AST_LIST_INSERT_HEAD(&zones, z, list);
12464 AST_LIST_UNLOCK(&zones);
12465 } else {
12466 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12467 ast_free(z);
12468 }
12469 } else {
12470 AST_LIST_UNLOCK(&users);
12471 return -1;
12472 }
12473 var = var->next;
12474 }
12475 }
12476 }
12477 cat = ast_category_browse(cfg, cat);
12478 }
12479
12480 AST_LIST_UNLOCK(&users);
12481
12482 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12483 start_poll_thread();
12484 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12485 stop_poll_thread();;
12486
12487 return 0;
12488 } else {
12489 AST_LIST_UNLOCK(&users);
12490 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12491 return 0;
12492 }
12493 }
12494
12495 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12496 {
12497 int res = -1;
12498 char dir[PATH_MAX];
12499 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12500 ast_debug(2, "About to try retrieving name file %s\n", dir);
12501 RETRIEVE(dir, -1, mailbox, context);
12502 if (ast_fileexists(dir, NULL, NULL)) {
12503 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12504 }
12505 DISPOSE(dir, -1);
12506 return res;
12507 }
12508
12509 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12510 struct ast_config *pwconf;
12511 struct ast_flags config_flags = { 0 };
12512
12513 pwconf = ast_config_load(secretfn, config_flags);
12514 if (pwconf) {
12515 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12516 if (val) {
12517 ast_copy_string(password, val, passwordlen);
12518 return;
12519 }
12520 }
12521 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12522 }
12523
12524 static int write_password_to_file(const char *secretfn, const char *password) {
12525 struct ast_config *conf;
12526 struct ast_category *cat;
12527 struct ast_variable *var;
12528
12529 if (!(conf=ast_config_new())) {
12530 ast_log(LOG_ERROR, "Error creating new config structure\n");
12531 return -1;
12532 }
12533 if (!(cat=ast_category_new("general","",1))) {
12534 ast_log(LOG_ERROR, "Error creating new category structure\n");
12535 return -1;
12536 }
12537 if (!(var=ast_variable_new("password",password,""))) {
12538 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12539 return -1;
12540 }
12541 ast_category_append(conf,cat);
12542 ast_variable_append(cat,var);
12543 if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12544 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12545 return -1;
12546 }
12547 return 0;
12548 }
12549
12550 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12551 {
12552 char *context;
12553 char *args_copy;
12554 int res;
12555
12556 if (ast_strlen_zero(data)) {
12557 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context");
12558 return -1;
12559 }
12560
12561 args_copy = ast_strdupa(data);
12562 if ((context = strchr(args_copy, '@'))) {
12563 *context++ = '\0';
12564 } else {
12565 context = "default";
12566 }
12567
12568 if ((res = sayname(chan, args_copy, context) < 0)) {
12569 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12570 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12571 if (!res) {
12572 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12573 }
12574 }
12575
12576 return res;
12577 }
12578
12579 #ifdef TEST_FRAMEWORK
12580 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12581 {
12582 return 0;
12583 }
12584
12585 static struct ast_frame *fake_read(struct ast_channel *ast)
12586 {
12587 return &ast_null_frame;
12588 }
12589
12590 AST_TEST_DEFINE(test_voicemail_vmsayname)
12591 {
12592 char dir[PATH_MAX];
12593 char dir2[PATH_MAX];
12594 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12595 static const char TEST_EXTENSION[] = "1234";
12596
12597 struct ast_channel *test_channel1 = NULL;
12598 int res = -1;
12599
12600 static const struct ast_channel_tech fake_tech = {
12601 .write = fake_write,
12602 .read = fake_read,
12603 };
12604
12605 switch (cmd) {
12606 case TEST_INIT:
12607 info->name = "vmsayname_exec";
12608 info->category = "/apps/app_voicemail/";
12609 info->summary = "Vmsayname unit test";
12610 info->description =
12611 "This tests passing various parameters to vmsayname";
12612 return AST_TEST_NOT_RUN;
12613 case TEST_EXECUTE:
12614 break;
12615 }
12616
12617 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12618 NULL, NULL, 0, 0, "TestChannel1"))) {
12619 goto exit_vmsayname_test;
12620 }
12621
12622
12623 test_channel1->nativeformats = AST_FORMAT_GSM;
12624 test_channel1->writeformat = AST_FORMAT_GSM;
12625 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12626 test_channel1->readformat = AST_FORMAT_GSM;
12627 test_channel1->rawreadformat = AST_FORMAT_GSM;
12628 test_channel1->tech = &fake_tech;
12629
12630 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12631 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12632 if (!(res = vmsayname_exec(test_channel1, dir))) {
12633 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12634 if (ast_fileexists(dir, NULL, NULL)) {
12635 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12636 res = -1;
12637 goto exit_vmsayname_test;
12638 } else {
12639
12640 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12641 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12642 goto exit_vmsayname_test;
12643 }
12644 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12645 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12646
12647 if ((res = symlink(dir, dir2))) {
12648 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12649 goto exit_vmsayname_test;
12650 }
12651 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12652 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12653 res = vmsayname_exec(test_channel1, dir);
12654
12655
12656 unlink(dir2);
12657 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12658 rmdir(dir2);
12659 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12660 rmdir(dir2);
12661 }
12662 }
12663
12664 exit_vmsayname_test:
12665
12666 if (test_channel1) {
12667 ast_hangup(test_channel1);
12668 }
12669
12670 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12671 }
12672
12673 AST_TEST_DEFINE(test_voicemail_msgcount)
12674 {
12675 int i, j, res = AST_TEST_PASS, syserr;
12676 struct ast_vm_user *vmu;
12677 struct vm_state vms;
12678 #ifdef IMAP_STORAGE
12679 struct ast_channel *chan = NULL;
12680 #endif
12681 struct {
12682 char dir[256];
12683 char file[256];
12684 char txtfile[256];
12685 } tmp[3];
12686 char syscmd[256];
12687 const char origweasels[] = "tt-weasels";
12688 const char testcontext[] = "test";
12689 const char testmailbox[] = "00000000";
12690 const char testspec[] = "00000000@test";
12691 FILE *txt;
12692 int new, old, urgent;
12693 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12694 const int folder2mbox[3] = { 1, 11, 0 };
12695 const int expected_results[3][12] = {
12696
12697 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12698 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12699 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12700 };
12701
12702 switch (cmd) {
12703 case TEST_INIT:
12704 info->name = "test_voicemail_msgcount";
12705 info->category = "/apps/app_voicemail/";
12706 info->summary = "Test Voicemail status checks";
12707 info->description =
12708 "Verify that message counts are correct when retrieved through the public API";
12709 return AST_TEST_NOT_RUN;
12710 case TEST_EXECUTE:
12711 break;
12712 }
12713
12714
12715 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12716 if ((syserr = ast_safe_system(syscmd))) {
12717 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12718 syserr > 0 ? strerror(syserr) : "unable to fork()");
12719 return AST_TEST_FAIL;
12720 }
12721
12722 #ifdef IMAP_STORAGE
12723 if (!(chan = ast_dummy_channel_alloc())) {
12724 ast_test_status_update(test, "Unable to create dummy channel\n");
12725 return AST_TEST_FAIL;
12726 }
12727 #endif
12728
12729 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12730 !(vmu = find_or_create(testcontext, testmailbox))) {
12731 ast_test_status_update(test, "Cannot create vmu structure\n");
12732 ast_unreplace_sigchld();
12733 #ifdef IMAP_STORAGE
12734 chan = ast_channel_unref(chan);
12735 #endif
12736 return AST_TEST_FAIL;
12737 }
12738
12739 populate_defaults(vmu);
12740 memset(&vms, 0, sizeof(vms));
12741
12742
12743 for (i = 0; i < 3; i++) {
12744 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12745 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12746 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12747
12748 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12749 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12750 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12751 if ((syserr = ast_safe_system(syscmd))) {
12752 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12753 syserr > 0 ? strerror(syserr) : "unable to fork()");
12754 ast_unreplace_sigchld();
12755 #ifdef IMAP_STORAGE
12756 chan = ast_channel_unref(chan);
12757 #endif
12758 return AST_TEST_FAIL;
12759 }
12760 }
12761
12762 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12763 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12764 fclose(txt);
12765 } else {
12766 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12767 res = AST_TEST_FAIL;
12768 break;
12769 }
12770 open_mailbox(&vms, vmu, folder2mbox[i]);
12771 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12772
12773
12774 for (j = 0; j < 3; j++) {
12775
12776 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12777 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12778 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12779 res = AST_TEST_FAIL;
12780 }
12781 }
12782
12783 new = old = urgent = 0;
12784 if (ast_app_inboxcount(testspec, &new, &old)) {
12785 ast_test_status_update(test, "inboxcount returned failure\n");
12786 res = AST_TEST_FAIL;
12787 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12788 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12789 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12790 res = AST_TEST_FAIL;
12791 }
12792
12793 new = old = urgent = 0;
12794 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12795 ast_test_status_update(test, "inboxcount2 returned failure\n");
12796 res = AST_TEST_FAIL;
12797 } else if (old != expected_results[i][6 + 0] ||
12798 urgent != expected_results[i][6 + 1] ||
12799 new != expected_results[i][6 + 2] ) {
12800 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12801 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12802 res = AST_TEST_FAIL;
12803 }
12804
12805 new = old = urgent = 0;
12806 for (j = 0; j < 3; j++) {
12807 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12808 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12809 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12810 res = AST_TEST_FAIL;
12811 }
12812 }
12813 }
12814
12815 for (i = 0; i < 3; i++) {
12816
12817
12818
12819 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12820 DISPOSE(tmp[i].dir, 0);
12821 }
12822
12823 if (vms.deleted) {
12824 ast_free(vms.deleted);
12825 }
12826 if (vms.heard) {
12827 ast_free(vms.heard);
12828 }
12829
12830 #ifdef IMAP_STORAGE
12831 chan = ast_channel_unref(chan);
12832 #endif
12833
12834
12835 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12836 if ((syserr = ast_safe_system(syscmd))) {
12837 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12838 syserr > 0 ? strerror(syserr) : "unable to fork()");
12839 }
12840
12841 return res;
12842 }
12843
12844 AST_TEST_DEFINE(test_voicemail_notify_endl)
12845 {
12846 int res = AST_TEST_PASS;
12847 char testcontext[] = "test";
12848 char testmailbox[] = "00000000";
12849 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12850 char attach[256], attach2[256];
12851 char buf[256] = "";
12852 struct ast_channel *chan = NULL;
12853 struct ast_vm_user *vmu, vmus = {
12854 .flags = 0,
12855 };
12856 FILE *file;
12857 struct {
12858 char *name;
12859 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12860 void *location;
12861 union {
12862 int intval;
12863 char *strval;
12864 } u;
12865 } test_items[] = {
12866 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12867 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12868 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12869 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12870 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12871 { "attach2", STRPTR, attach2, .u.strval = "" },
12872 { "attach", STRPTR, attach, .u.strval = "" },
12873 };
12874 int which;
12875
12876 switch (cmd) {
12877 case TEST_INIT:
12878 info->name = "test_voicemail_notify_endl";
12879 info->category = "/apps/app_voicemail/";
12880 info->summary = "Test Voicemail notification end-of-line";
12881 info->description =
12882 "Verify that notification emails use a consistent end-of-line character";
12883 return AST_TEST_NOT_RUN;
12884 case TEST_EXECUTE:
12885 break;
12886 }
12887
12888 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12889 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12890
12891 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12892 !(vmu = find_or_create(testcontext, testmailbox))) {
12893 ast_test_status_update(test, "Cannot create vmu structure\n");
12894 return AST_TEST_NOT_RUN;
12895 }
12896
12897 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12898 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12899 return AST_TEST_NOT_RUN;
12900 }
12901
12902 populate_defaults(vmu);
12903 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12904 #ifdef IMAP_STORAGE
12905
12906 #endif
12907
12908 file = tmpfile();
12909 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12910
12911 rewind(file);
12912 if (ftruncate(fileno(file), 0)) {
12913 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12914 res = AST_TEST_FAIL;
12915 break;
12916 }
12917
12918
12919 if (test_items[which].type == INT) {
12920 *((int *) test_items[which].location) = test_items[which].u.intval;
12921 } else if (test_items[which].type == FLAGVAL) {
12922 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12923 ast_clear_flag(vmu, test_items[which].u.intval);
12924 } else {
12925 ast_set_flag(vmu, test_items[which].u.intval);
12926 }
12927 } else if (test_items[which].type == STATIC) {
12928 strcpy(test_items[which].location, test_items[which].u.strval);
12929 } else if (test_items[which].type == STRPTR) {
12930 test_items[which].location = test_items[which].u.strval;
12931 }
12932
12933 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12934 rewind(file);
12935 while (fgets(buf, sizeof(buf), file)) {
12936 if (
12937 #ifdef IMAP_STORAGE
12938 buf[strlen(buf) - 2] != '\r'
12939 #else
12940 buf[strlen(buf) - 2] == '\r'
12941 #endif
12942 || buf[strlen(buf) - 1] != '\n') {
12943 res = AST_TEST_FAIL;
12944 }
12945 }
12946 }
12947 fclose(file);
12948 return res;
12949 }
12950
12951 AST_TEST_DEFINE(test_voicemail_load_config)
12952 {
12953 int res = AST_TEST_PASS;
12954 struct ast_vm_user *vmu;
12955 struct ast_config *cfg;
12956 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
12957 int fd;
12958 FILE *file;
12959 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
12960
12961 switch (cmd) {
12962 case TEST_INIT:
12963 info->name = "test_voicemail_load_config";
12964 info->category = "/apps/app_voicemail/";
12965 info->summary = "Test loading Voicemail config";
12966 info->description =
12967 "Verify that configuration is loaded consistently. "
12968 "This is to test regressions of ASTERISK-18838 where it was noticed that "
12969 "some options were loaded after the mailboxes were instantiated, causing "
12970 "those options not to be set correctly.";
12971 return AST_TEST_NOT_RUN;
12972 case TEST_EXECUTE:
12973 break;
12974 }
12975
12976
12977 if ((fd = mkstemp(config_filename)) < 0) {
12978 return AST_TEST_FAIL;
12979 }
12980 if (!(file = fdopen(fd, "w"))) {
12981 close(fd);
12982 unlink(config_filename);
12983 return AST_TEST_FAIL;
12984 }
12985 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
12986 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
12987 fputs("00000002 => 9999,Mrs. Test\n", file);
12988 fclose(file);
12989
12990 if (!(cfg = ast_config_load(config_filename, config_flags))) {
12991 res = AST_TEST_FAIL;
12992 goto cleanup;
12993 }
12994
12995 load_config_from_memory(1, cfg, NULL);
12996 ast_config_destroy(cfg);
12997
12998 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
12999 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13000 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13001
13002 AST_LIST_LOCK(&users);
13003 AST_LIST_TRAVERSE(&users, vmu, list) {
13004 if (!strcmp(vmu->mailbox, "00000001")) {
13005 if (0);
13006 CHECK(vmu, callback, "othercontext")
13007 CHECK(vmu, locale, "nl_NL.UTF-8")
13008 CHECK(vmu, zonetag, "central")
13009 } else if (!strcmp(vmu->mailbox, "00000002")) {
13010 if (0);
13011 CHECK(vmu, callback, "somecontext")
13012 CHECK(vmu, locale, "de_DE.UTF-8")
13013 CHECK(vmu, zonetag, "european")
13014 }
13015 }
13016 AST_LIST_UNLOCK(&users);
13017
13018 #undef CHECK
13019
13020
13021 load_config(1);
13022
13023 cleanup:
13024 unlink(config_filename);
13025 return res;
13026 }
13027
13028 #endif
13029
13030 static int reload(void)
13031 {
13032 return load_config(1);
13033 }
13034
13035 static int unload_module(void)
13036 {
13037 int res;
13038
13039 res = ast_unregister_application(app);
13040 res |= ast_unregister_application(app2);
13041 res |= ast_unregister_application(app3);
13042 res |= ast_unregister_application(app4);
13043 res |= ast_unregister_application(sayname_app);
13044 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13045 res |= ast_manager_unregister("VoicemailUsersList");
13046 res |= ast_data_unregister(NULL);
13047 #ifdef TEST_FRAMEWORK
13048 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13049 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13050 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13051 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13052 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13053 #endif
13054 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13055 ast_uninstall_vm_functions();
13056 ao2_ref(inprocess_container, -1);
13057
13058 if (poll_thread != AST_PTHREADT_NULL)
13059 stop_poll_thread();
13060
13061 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13062 ast_unload_realtime("voicemail");
13063 ast_unload_realtime("voicemail_data");
13064
13065 free_vm_users();
13066 free_vm_zones();
13067 return res;
13068 }
13069
13070 static int load_module(void)
13071 {
13072 int res;
13073 my_umask = umask(0);
13074 umask(my_umask);
13075
13076 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13077 return AST_MODULE_LOAD_DECLINE;
13078 }
13079
13080
13081 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13082
13083 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13084 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13085 }
13086
13087 if ((res = load_config(0)))
13088 return res;
13089
13090 res = ast_register_application_xml(app, vm_exec);
13091 res |= ast_register_application_xml(app2, vm_execmain);
13092 res |= ast_register_application_xml(app3, vm_box_exists);
13093 res |= ast_register_application_xml(app4, vmauthenticate);
13094 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13095 res |= ast_custom_function_register(&mailbox_exists_acf);
13096 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13097 #ifdef TEST_FRAMEWORK
13098 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13099 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13100 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13101 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13102 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13103 #endif
13104
13105 if (res)
13106 return res;
13107
13108 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13109 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13110
13111 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13112 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13113 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13114
13115 return res;
13116 }
13117
13118 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13119 {
13120 int cmd = 0;
13121 char destination[80] = "";
13122 int retries = 0;
13123
13124 if (!num) {
13125 ast_verb(3, "Destination number will be entered manually\n");
13126 while (retries < 3 && cmd != 't') {
13127 destination[1] = '\0';
13128 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13129 if (!cmd)
13130 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13131 if (!cmd)
13132 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13133 if (!cmd) {
13134 cmd = ast_waitfordigit(chan, 6000);
13135 if (cmd)
13136 destination[0] = cmd;
13137 }
13138 if (!cmd) {
13139 retries++;
13140 } else {
13141
13142 if (cmd < 0)
13143 return 0;
13144 if (cmd == '*') {
13145 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13146 return 0;
13147 }
13148 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13149 retries++;
13150 else
13151 cmd = 't';
13152 }
13153 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13154 }
13155 if (retries >= 3) {
13156 return 0;
13157 }
13158
13159 } else {
13160 if (option_verbose > 2)
13161 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13162 ast_copy_string(destination, num, sizeof(destination));
13163 }
13164
13165 if (!ast_strlen_zero(destination)) {
13166 if (destination[strlen(destination) -1 ] == '*')
13167 return 0;
13168 if (option_verbose > 2)
13169 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13170 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13171 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13172 chan->priority = 0;
13173 return 9;
13174 }
13175 return 0;
13176 }
13177
13178
13179
13180
13181
13182
13183
13184
13185
13186
13187
13188
13189
13190
13191 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)
13192 {
13193 int res = 0;
13194 char filename[PATH_MAX];
13195 struct ast_config *msg_cfg = NULL;
13196 const char *origtime, *context;
13197 char *name, *num;
13198 int retries = 0;
13199 char *cid;
13200 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13201
13202 vms->starting = 0;
13203
13204 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13205
13206
13207 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13208 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13209 msg_cfg = ast_config_load(filename, config_flags);
13210 DISPOSE(vms->curdir, vms->curmsg);
13211 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13212 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13213 return 0;
13214 }
13215
13216 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13217 ast_config_destroy(msg_cfg);
13218 return 0;
13219 }
13220
13221 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13222
13223 context = ast_variable_retrieve(msg_cfg, "message", "context");
13224 if (!strncasecmp("macro", context, 5))
13225 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13226 switch (option) {
13227 case 3:
13228 if (!res)
13229 res = play_message_datetime(chan, vmu, origtime, filename);
13230 if (!res)
13231 res = play_message_callerid(chan, vms, cid, context, 0);
13232
13233 res = 't';
13234 break;
13235
13236 case 2:
13237
13238 if (ast_strlen_zero(cid))
13239 break;
13240
13241 ast_callerid_parse(cid, &name, &num);
13242 while ((res > -1) && (res != 't')) {
13243 switch (res) {
13244 case '1':
13245 if (num) {
13246
13247 res = dialout(chan, vmu, num, vmu->callback);
13248 if (res) {
13249 ast_config_destroy(msg_cfg);
13250 return 9;
13251 }
13252 } else {
13253 res = '2';
13254 }
13255 break;
13256
13257 case '2':
13258
13259 if (!ast_strlen_zero(vmu->dialout)) {
13260 res = dialout(chan, vmu, NULL, vmu->dialout);
13261 if (res) {
13262 ast_config_destroy(msg_cfg);
13263 return 9;
13264 }
13265 } else {
13266 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13267 res = ast_play_and_wait(chan, "vm-sorry");
13268 }
13269 ast_config_destroy(msg_cfg);
13270 return res;
13271 case '*':
13272 res = 't';
13273 break;
13274 case '3':
13275 case '4':
13276 case '5':
13277 case '6':
13278 case '7':
13279 case '8':
13280 case '9':
13281 case '0':
13282
13283 res = ast_play_and_wait(chan, "vm-sorry");
13284 retries++;
13285 break;
13286 default:
13287 if (num) {
13288 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13289 res = ast_play_and_wait(chan, "vm-num-i-have");
13290 if (!res)
13291 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13292 if (!res)
13293 res = ast_play_and_wait(chan, "vm-tocallnum");
13294
13295 if (!ast_strlen_zero(vmu->dialout)) {
13296 if (!res)
13297 res = ast_play_and_wait(chan, "vm-calldiffnum");
13298 }
13299 } else {
13300 res = ast_play_and_wait(chan, "vm-nonumber");
13301 if (!ast_strlen_zero(vmu->dialout)) {
13302 if (!res)
13303 res = ast_play_and_wait(chan, "vm-toenternumber");
13304 }
13305 }
13306 if (!res) {
13307 res = ast_play_and_wait(chan, "vm-star-cancel");
13308 }
13309 if (!res) {
13310 res = ast_waitfordigit(chan, 6000);
13311 }
13312 if (!res) {
13313 retries++;
13314 if (retries > 3) {
13315 res = 't';
13316 }
13317 }
13318 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13319 break;
13320
13321 }
13322 if (res == 't')
13323 res = 0;
13324 else if (res == '*')
13325 res = -1;
13326 }
13327 break;
13328
13329 case 1:
13330
13331 if (ast_strlen_zero(cid))
13332 break;
13333
13334 ast_callerid_parse(cid, &name, &num);
13335 if (!num) {
13336 ast_verb(3, "No CID number available, no reply sent\n");
13337 if (!res)
13338 res = ast_play_and_wait(chan, "vm-nonumber");
13339 ast_config_destroy(msg_cfg);
13340 return res;
13341 } else {
13342 struct ast_vm_user vmu2;
13343 if (find_user(&vmu2, vmu->context, num)) {
13344 struct leave_vm_options leave_options;
13345 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13346 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13347
13348 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13349
13350 memset(&leave_options, 0, sizeof(leave_options));
13351 leave_options.record_gain = record_gain;
13352 res = leave_voicemail(chan, mailbox, &leave_options);
13353 if (!res)
13354 res = 't';
13355 ast_config_destroy(msg_cfg);
13356 return res;
13357 } else {
13358
13359 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13360 ast_play_and_wait(chan, "vm-nobox");
13361 res = 't';
13362 ast_config_destroy(msg_cfg);
13363 return res;
13364 }
13365 }
13366 res = 0;
13367
13368 break;
13369 }
13370
13371 #ifndef IMAP_STORAGE
13372 ast_config_destroy(msg_cfg);
13373
13374 if (!res) {
13375 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13376 vms->heard[msg] = 1;
13377 res = wait_file(chan, vms, vms->fn);
13378 }
13379 #endif
13380 return res;
13381 }
13382
13383 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13384 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13385 signed char record_gain, struct vm_state *vms, char *flag)
13386 {
13387
13388 int res = 0;
13389 int cmd = 0;
13390 int max_attempts = 3;
13391 int attempts = 0;
13392 int recorded = 0;
13393 int msg_exists = 0;
13394 signed char zero_gain = 0;
13395 char tempfile[PATH_MAX];
13396 char *acceptdtmf = "#";
13397 char *canceldtmf = "";
13398 int canceleddtmf = 0;
13399
13400
13401
13402
13403 if (duration == NULL) {
13404 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13405 return -1;
13406 }
13407
13408 if (!outsidecaller)
13409 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13410 else
13411 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13412
13413 cmd = '3';
13414
13415 while ((cmd >= 0) && (cmd != 't')) {
13416 switch (cmd) {
13417 case '1':
13418 if (!msg_exists) {
13419
13420 cmd = '3';
13421 break;
13422 } else {
13423
13424 ast_verb(3, "Saving message as is\n");
13425 if (!outsidecaller)
13426 ast_filerename(tempfile, recordfile, NULL);
13427 ast_stream_and_wait(chan, "vm-msgsaved", "");
13428 if (!outsidecaller) {
13429
13430 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13431 DISPOSE(recordfile, -1);
13432 }
13433 cmd = 't';
13434 return res;
13435 }
13436 case '2':
13437
13438 ast_verb(3, "Reviewing the message\n");
13439 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13440 break;
13441 case '3':
13442 msg_exists = 0;
13443
13444 if (recorded == 1)
13445 ast_verb(3, "Re-recording the message\n");
13446 else
13447 ast_verb(3, "Recording the message\n");
13448
13449 if (recorded && outsidecaller) {
13450 cmd = ast_play_and_wait(chan, INTRO);
13451 cmd = ast_play_and_wait(chan, "beep");
13452 }
13453 recorded = 1;
13454
13455 if (record_gain)
13456 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13457 if (ast_test_flag(vmu, VM_OPERATOR))
13458 canceldtmf = "0";
13459 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13460 if (strchr(canceldtmf, cmd)) {
13461
13462 canceleddtmf = 1;
13463 }
13464 if (record_gain)
13465 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13466 if (cmd == -1) {
13467
13468 if (!outsidecaller) {
13469
13470 ast_filedelete(tempfile, NULL);
13471 }
13472 return cmd;
13473 }
13474 if (cmd == '0') {
13475 break;
13476 } else if (cmd == '*') {
13477 break;
13478 #if 0
13479 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13480
13481 ast_verb(3, "Message too short\n");
13482 cmd = ast_play_and_wait(chan, "vm-tooshort");
13483 cmd = ast_filedelete(tempfile, NULL);
13484 break;
13485 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13486
13487 ast_verb(3, "Nothing recorded\n");
13488 cmd = ast_filedelete(tempfile, NULL);
13489 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13490 if (!cmd)
13491 cmd = ast_play_and_wait(chan, "vm-speakup");
13492 break;
13493 #endif
13494 } else {
13495
13496 msg_exists = 1;
13497 cmd = 0;
13498 }
13499 break;
13500 case '4':
13501 if (outsidecaller) {
13502
13503 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13504 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13505 res = ast_play_and_wait(chan, "vm-marked-urgent");
13506 strcpy(flag, "Urgent");
13507 } else if (flag) {
13508 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13509 res = ast_play_and_wait(chan, "vm-urgent-removed");
13510 strcpy(flag, "");
13511 } else {
13512 ast_play_and_wait(chan, "vm-sorry");
13513 }
13514 cmd = 0;
13515 } else {
13516 cmd = ast_play_and_wait(chan, "vm-sorry");
13517 }
13518 break;
13519 case '5':
13520 case '6':
13521 case '7':
13522 case '8':
13523 case '9':
13524 case '*':
13525 case '#':
13526 cmd = ast_play_and_wait(chan, "vm-sorry");
13527 break;
13528 #if 0
13529
13530
13531 case '*':
13532
13533 cmd = ast_play_and_wait(chan, "vm-deleted");
13534 cmd = ast_filedelete(tempfile, NULL);
13535 if (outsidecaller) {
13536 res = vm_exec(chan, NULL);
13537 return res;
13538 }
13539 else
13540 return 1;
13541 #endif
13542 case '0':
13543 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13544 cmd = ast_play_and_wait(chan, "vm-sorry");
13545 break;
13546 }
13547 if (msg_exists || recorded) {
13548 cmd = ast_play_and_wait(chan, "vm-saveoper");
13549 if (!cmd)
13550 cmd = ast_waitfordigit(chan, 3000);
13551 if (cmd == '1') {
13552 ast_filerename(tempfile, recordfile, NULL);
13553 ast_play_and_wait(chan, "vm-msgsaved");
13554 cmd = '0';
13555 } else if (cmd == '4') {
13556 if (flag) {
13557 ast_play_and_wait(chan, "vm-marked-urgent");
13558 strcpy(flag, "Urgent");
13559 }
13560 ast_play_and_wait(chan, "vm-msgsaved");
13561 cmd = '0';
13562 } else {
13563 ast_play_and_wait(chan, "vm-deleted");
13564 DELETE(tempfile, -1, tempfile, vmu);
13565 cmd = '0';
13566 }
13567 }
13568 return cmd;
13569 default:
13570
13571
13572
13573 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13574 return cmd;
13575 if (msg_exists) {
13576 cmd = ast_play_and_wait(chan, "vm-review");
13577 if (!cmd && outsidecaller) {
13578 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13579 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13580 } else if (flag) {
13581 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13582 }
13583 }
13584 } else {
13585 cmd = ast_play_and_wait(chan, "vm-torerecord");
13586 if (!cmd)
13587 cmd = ast_waitfordigit(chan, 600);
13588 }
13589
13590 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13591 cmd = ast_play_and_wait(chan, "vm-reachoper");
13592 if (!cmd)
13593 cmd = ast_waitfordigit(chan, 600);
13594 }
13595 #if 0
13596 if (!cmd)
13597 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13598 #endif
13599 if (!cmd)
13600 cmd = ast_waitfordigit(chan, 6000);
13601 if (!cmd) {
13602 attempts++;
13603 }
13604 if (attempts > max_attempts) {
13605 cmd = 't';
13606 }
13607 }
13608 }
13609 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13610
13611 ast_filedelete(tempfile, NULL);
13612 }
13613
13614 if (cmd != 't' && outsidecaller)
13615 ast_play_and_wait(chan, "vm-goodbye");
13616
13617 return cmd;
13618 }
13619
13620
13621
13622
13623
13624 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13625 .load = load_module,
13626 .unload = unload_module,
13627 .reload = reload,
13628 .nonoptreq = "res_adsi,res_smdi",
13629 );