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