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: 426691 $")
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 language[MAX_LANGUAGE];
00652 char zonetag[80];
00653 char locale[20];
00654 char callback[80];
00655 char dialout[80];
00656 char uniqueid[80];
00657 char exit[80];
00658 char attachfmt[20];
00659 unsigned int flags;
00660 int saydurationm;
00661 int minsecs;
00662 int maxmsg;
00663 int maxdeletedmsg;
00664 int maxsecs;
00665 int passwordlocation;
00666 #ifdef IMAP_STORAGE
00667 char imapuser[80];
00668 char imappassword[80];
00669 char imapfolder[64];
00670 char imapvmshareid[80];
00671 int imapversion;
00672 #endif
00673 double volgain;
00674 AST_LIST_ENTRY(ast_vm_user) list;
00675 };
00676
00677
00678 struct vm_zone {
00679 AST_LIST_ENTRY(vm_zone) list;
00680 char name[80];
00681 char timezone[80];
00682 char msg_format[512];
00683 };
00684
00685 #define VMSTATE_MAX_MSG_ARRAY 256
00686
00687
00688 struct vm_state {
00689 char curbox[80];
00690 char username[80];
00691 char context[80];
00692 char curdir[PATH_MAX];
00693 char vmbox[PATH_MAX];
00694 char fn[PATH_MAX];
00695 char intro[PATH_MAX];
00696 int *deleted;
00697 int *heard;
00698 int dh_arraysize;
00699 int curmsg;
00700 int lastmsg;
00701 int newmessages;
00702 int oldmessages;
00703 int urgentmessages;
00704 int starting;
00705 int repeats;
00706 #ifdef IMAP_STORAGE
00707 ast_mutex_t lock;
00708 int updated;
00709 long *msgArray;
00710 unsigned msg_array_max;
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 = ast_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 memset(retval, 0, sizeof(*retval));
01412 }
01413 populate_defaults(retval);
01414 if (!ivm) {
01415 ast_set_flag(retval, VM_ALLOCED);
01416 }
01417 if (mailbox) {
01418 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01419 }
01420 if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
01421 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01422 } else {
01423 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01424 }
01425 if (var) {
01426 apply_options_full(retval, var);
01427 ast_variables_destroy(var);
01428 } else {
01429 if (!ivm)
01430 free_user(retval);
01431 retval = NULL;
01432 }
01433 }
01434 return retval;
01435 }
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01446 {
01447
01448 struct ast_vm_user *vmu = NULL, *cur;
01449 AST_LIST_LOCK(&users);
01450
01451 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01452 context = "default";
01453
01454 AST_LIST_TRAVERSE(&users, cur, list) {
01455 #ifdef IMAP_STORAGE
01456 if (cur->imapversion != imapversion) {
01457 continue;
01458 }
01459 #endif
01460 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01461 break;
01462 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01463 break;
01464 }
01465 if (cur) {
01466
01467 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01468 *vmu = *cur;
01469 if (!ivm) {
01470 vmu->emailbody = ast_strdup(cur->emailbody);
01471 vmu->emailsubject = ast_strdup(cur->emailsubject);
01472 }
01473 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01474 AST_LIST_NEXT(vmu, list) = NULL;
01475 }
01476 } else
01477 vmu = find_user_realtime(ivm, context, mailbox);
01478 AST_LIST_UNLOCK(&users);
01479 return vmu;
01480 }
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01493 {
01494
01495 struct ast_vm_user *cur;
01496 int res = -1;
01497 AST_LIST_LOCK(&users);
01498 AST_LIST_TRAVERSE(&users, cur, list) {
01499 if ((!context || !strcasecmp(context, cur->context)) &&
01500 (!strcasecmp(mailbox, cur->mailbox)))
01501 break;
01502 }
01503 if (cur) {
01504 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01505 res = 0;
01506 }
01507 AST_LIST_UNLOCK(&users);
01508 return res;
01509 }
01510
01511
01512
01513
01514 static inline int valid_config(const struct ast_config *cfg)
01515 {
01516 return cfg && cfg != CONFIG_STATUS_FILEINVALID;
01517 }
01518
01519
01520
01521
01522
01523
01524
01525
01526 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01527 {
01528 struct ast_config *cfg = NULL;
01529 struct ast_variable *var = NULL;
01530 struct ast_category *cat = NULL;
01531 char *category = NULL, *value = NULL, *new = NULL;
01532 const char *tmp = NULL;
01533 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01534 char secretfn[PATH_MAX] = "";
01535 int found = 0;
01536
01537 if (!change_password_realtime(vmu, newpassword))
01538 return;
01539
01540
01541 switch (vmu->passwordlocation) {
01542 case OPT_PWLOC_SPOOLDIR:
01543 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01544 if (write_password_to_file(secretfn, newpassword) == 0) {
01545 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01546 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01547 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01548 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01549 break;
01550 } else {
01551 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01552 }
01553
01554 case OPT_PWLOC_VOICEMAILCONF:
01555 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
01556 while ((category = ast_category_browse(cfg, category))) {
01557 if (!strcasecmp(category, vmu->context)) {
01558 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01559 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01560 break;
01561 }
01562 value = strstr(tmp, ",");
01563 if (!value) {
01564 new = ast_alloca(strlen(newpassword)+1);
01565 sprintf(new, "%s", newpassword);
01566 } else {
01567 new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
01568 sprintf(new, "%s%s", newpassword, value);
01569 }
01570 if (!(cat = ast_category_get(cfg, category))) {
01571 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01572 break;
01573 }
01574 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01575 found = 1;
01576 }
01577 }
01578
01579 if (found) {
01580 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01581 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01582 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01583 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01584 ast_config_destroy(cfg);
01585 break;
01586 }
01587
01588 ast_config_destroy(cfg);
01589 }
01590
01591 case OPT_PWLOC_USERSCONF:
01592
01593
01594 if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
01595 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01596 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01597 ast_debug(4, "users.conf: %s\n", category);
01598 if (!strcasecmp(category, vmu->mailbox)) {
01599 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01600 ast_debug(3, "looks like we need to make vmsecret!\n");
01601 var = ast_variable_new("vmsecret", newpassword, "");
01602 } else {
01603 var = NULL;
01604 }
01605 new = ast_alloca(strlen(newpassword) + 1);
01606 sprintf(new, "%s", newpassword);
01607 if (!(cat = ast_category_get(cfg, category))) {
01608 ast_debug(4, "failed to get category!\n");
01609 ast_free(var);
01610 break;
01611 }
01612 if (!var) {
01613 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01614 } else {
01615 ast_variable_append(cat, var);
01616 }
01617 found = 1;
01618 break;
01619 }
01620 }
01621
01622 if (found) {
01623 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01624 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01625 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01626 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01627 }
01628
01629 ast_config_destroy(cfg);
01630 }
01631 }
01632 }
01633
01634 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01635 {
01636 char buf[255];
01637 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01638 ast_debug(1, "External password: %s\n",buf);
01639 if (!ast_safe_system(buf)) {
01640 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01641 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01642
01643 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01644 }
01645 }
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01661 {
01662 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01663 }
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677 static int make_file(char *dest, const int len, const char *dir, const int num)
01678 {
01679 return snprintf(dest, len, "%s/msg%04d", dir, num);
01680 }
01681
01682
01683 static FILE *vm_mkftemp(char *template)
01684 {
01685 FILE *p = NULL;
01686 int pfd = mkstemp(template);
01687 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01688 if (pfd > -1) {
01689 p = fdopen(pfd, "w+");
01690 if (!p) {
01691 close(pfd);
01692 pfd = -1;
01693 }
01694 }
01695 return p;
01696 }
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01707 {
01708 mode_t mode = VOICEMAIL_DIR_MODE;
01709 int res;
01710
01711 make_dir(dest, len, context, ext, folder);
01712 if ((res = ast_mkdir(dest, mode))) {
01713 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01714 return -1;
01715 }
01716 return 0;
01717 }
01718
01719 static const char * const mailbox_folders[] = {
01720 #ifdef IMAP_STORAGE
01721 imapfolder,
01722 #else
01723 "INBOX",
01724 #endif
01725 "Old",
01726 "Work",
01727 "Family",
01728 "Friends",
01729 "Cust1",
01730 "Cust2",
01731 "Cust3",
01732 "Cust4",
01733 "Cust5",
01734 "Deleted",
01735 "Urgent",
01736 };
01737
01738 static const char *mbox(struct ast_vm_user *vmu, int id)
01739 {
01740 #ifdef IMAP_STORAGE
01741 if (vmu && id == 0) {
01742 return vmu->imapfolder;
01743 }
01744 #endif
01745 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01746 }
01747
01748 static int get_folder_by_name(const char *name)
01749 {
01750 size_t i;
01751
01752 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01753 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01754 return i;
01755 }
01756 }
01757
01758 return -1;
01759 }
01760
01761 static void free_user(struct ast_vm_user *vmu)
01762 {
01763 if (ast_test_flag(vmu, VM_ALLOCED)) {
01764
01765 ast_free(vmu->emailbody);
01766 vmu->emailbody = NULL;
01767
01768 ast_free(vmu->emailsubject);
01769 vmu->emailsubject = NULL;
01770
01771 ast_free(vmu);
01772 }
01773 }
01774
01775 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01776
01777 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01778
01779
01780 if (vms->deleted) {
01781 ast_free(vms->deleted);
01782 vms->deleted = NULL;
01783 }
01784 if (vms->heard) {
01785 ast_free(vms->heard);
01786 vms->heard = NULL;
01787 }
01788 vms->dh_arraysize = 0;
01789
01790 if (arraysize > 0) {
01791 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01792 return -1;
01793 }
01794 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01795 ast_free(vms->deleted);
01796 vms->deleted = NULL;
01797 return -1;
01798 }
01799 vms->dh_arraysize = arraysize;
01800 }
01801
01802 return 0;
01803 }
01804
01805
01806
01807 #ifdef IMAP_STORAGE
01808 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01809 {
01810 char arg[10];
01811 struct vm_state *vms;
01812 unsigned long messageNum;
01813
01814
01815 if (msgnum < 0 && !imapgreetings) {
01816 ast_filedelete(file, NULL);
01817 return;
01818 }
01819
01820 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01821 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);
01822 return;
01823 }
01824
01825 if (msgnum < 0) {
01826 imap_delete_old_greeting(file, vms);
01827 return;
01828 }
01829
01830
01831
01832 messageNum = vms->msgArray[msgnum];
01833 if (messageNum == 0) {
01834 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01835 return;
01836 }
01837 if (option_debug > 2)
01838 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01839
01840 snprintf (arg, sizeof(arg), "%lu", messageNum);
01841 ast_mutex_lock(&vms->lock);
01842 mail_setflag (vms->mailstream, arg, "\\DELETED");
01843 mail_expunge(vms->mailstream);
01844 ast_mutex_unlock(&vms->lock);
01845 }
01846
01847 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01848 {
01849 struct vm_state *vms_p;
01850 char *file, *filename;
01851 char *attachment;
01852 int i;
01853 BODY *body;
01854
01855
01856
01857
01858 if (msgnum > -1 || !imapgreetings) {
01859 return 0;
01860 } else {
01861 file = strrchr(ast_strdupa(dir), '/');
01862 if (file)
01863 *file++ = '\0';
01864 else {
01865 ast_debug (1, "Failed to procure file name from directory passed.\n");
01866 return -1;
01867 }
01868 }
01869
01870
01871 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01872 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01873
01874
01875
01876
01877 if (!(vms_p = create_vm_state_from_user(vmu))) {
01878 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01879 return -1;
01880 }
01881 }
01882
01883
01884 *vms_p->introfn = '\0';
01885
01886 ast_mutex_lock(&vms_p->lock);
01887 init_mailstream(vms_p, GREETINGS_FOLDER);
01888 if (!vms_p->mailstream) {
01889 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01890 ast_mutex_unlock(&vms_p->lock);
01891 return -1;
01892 }
01893
01894
01895 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01896 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01897
01898 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01899 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01900 } else {
01901 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01902 ast_mutex_unlock(&vms_p->lock);
01903 return -1;
01904 }
01905 filename = strsep(&attachment, ".");
01906 if (!strcmp(filename, file)) {
01907 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01908 vms_p->msgArray[vms_p->curmsg] = i + 1;
01909 save_body(body, vms_p, "2", attachment, 0);
01910 ast_mutex_unlock(&vms_p->lock);
01911 return 0;
01912 }
01913 }
01914 ast_mutex_unlock(&vms_p->lock);
01915
01916 return -1;
01917 }
01918
01919 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01920 {
01921 BODY *body;
01922 char *header_content;
01923 char *attachedfilefmt;
01924 char buf[80];
01925 struct vm_state *vms;
01926 char text_file[PATH_MAX];
01927 FILE *text_file_ptr;
01928 int res = 0;
01929 struct ast_vm_user *vmu;
01930
01931 if (!(vmu = find_user(NULL, context, mailbox))) {
01932 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01933 return -1;
01934 }
01935
01936 if (msgnum < 0) {
01937 if (imapgreetings) {
01938 res = imap_retrieve_greeting(dir, msgnum, vmu);
01939 goto exit;
01940 } else {
01941 res = 0;
01942 goto exit;
01943 }
01944 }
01945
01946
01947
01948
01949 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01950
01951
01952
01953
01954
01955
01956
01957 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01958 res = -1;
01959 goto exit;
01960 }
01961
01962 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01963 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01964
01965
01966 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01967 res = 0;
01968 goto exit;
01969 }
01970
01971 if (option_debug > 2)
01972 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01973 if (vms->msgArray[msgnum] == 0) {
01974 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01975 res = -1;
01976 goto exit;
01977 }
01978
01979
01980 ast_mutex_lock(&vms->lock);
01981 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01982 ast_mutex_unlock(&vms->lock);
01983
01984 if (ast_strlen_zero(header_content)) {
01985 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01986 res = -1;
01987 goto exit;
01988 }
01989
01990 ast_mutex_lock(&vms->lock);
01991 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01992 ast_mutex_unlock(&vms->lock);
01993
01994
01995 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01996 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01997 } else {
01998 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01999 res = -1;
02000 goto exit;
02001 }
02002
02003
02004
02005 strsep(&attachedfilefmt, ".");
02006 if (!attachedfilefmt) {
02007 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
02008 res = -1;
02009 goto exit;
02010 }
02011
02012 save_body(body, vms, "2", attachedfilefmt, 0);
02013 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
02014 *vms->introfn = '\0';
02015 }
02016
02017
02018 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
02019
02020 if (!(text_file_ptr = fopen(text_file, "w"))) {
02021 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
02022 }
02023
02024 fprintf(text_file_ptr, "%s\n", "[message]");
02025
02026 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02027 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02028 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02029 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02030 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02031 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02032 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02033 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02034 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02035 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02036 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02037 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02038 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02039 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02040 fclose(text_file_ptr);
02041
02042 exit:
02043 free_user(vmu);
02044 return res;
02045 }
02046
02047 static int folder_int(const char *folder)
02048 {
02049
02050 if (!folder) {
02051 return 0;
02052 }
02053 if (!strcasecmp(folder, imapfolder)) {
02054 return 0;
02055 } else if (!strcasecmp(folder, "Old")) {
02056 return 1;
02057 } else if (!strcasecmp(folder, "Work")) {
02058 return 2;
02059 } else if (!strcasecmp(folder, "Family")) {
02060 return 3;
02061 } else if (!strcasecmp(folder, "Friends")) {
02062 return 4;
02063 } else if (!strcasecmp(folder, "Cust1")) {
02064 return 5;
02065 } else if (!strcasecmp(folder, "Cust2")) {
02066 return 6;
02067 } else if (!strcasecmp(folder, "Cust3")) {
02068 return 7;
02069 } else if (!strcasecmp(folder, "Cust4")) {
02070 return 8;
02071 } else if (!strcasecmp(folder, "Cust5")) {
02072 return 9;
02073 } else if (!strcasecmp(folder, "Urgent")) {
02074 return 11;
02075 } else {
02076 return 0;
02077 }
02078 }
02079
02080 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02081 {
02082 SEARCHPGM *pgm;
02083 SEARCHHEADER *hdr;
02084
02085 struct ast_vm_user *vmu, vmus;
02086 struct vm_state *vms_p;
02087 int ret = 0;
02088 int fold = folder_int(folder);
02089 int urgent = 0;
02090
02091
02092 if (fold == 11) {
02093 fold = NEW_FOLDER;
02094 urgent = 1;
02095 }
02096
02097 if (ast_strlen_zero(mailbox))
02098 return 0;
02099
02100
02101 vmu = find_user(&vmus, context, mailbox);
02102 if (!vmu) {
02103 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02104 return -1;
02105 } else {
02106
02107 if (vmu->imapuser[0] == '\0') {
02108 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02109 return -1;
02110 }
02111 }
02112
02113
02114 if (vmu->imapuser[0] == '\0') {
02115 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02116 free_user(vmu);
02117 return -1;
02118 }
02119 ast_assert(msgnum < vms->msg_array_max);
02120
02121
02122 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02123 if (!vms_p) {
02124 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02125 }
02126 if (vms_p) {
02127 ast_debug(3, "Returning before search - user is logged in\n");
02128 if (fold == 0) {
02129 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02130 }
02131 if (fold == 1) {
02132 return vms_p->oldmessages;
02133 }
02134 }
02135
02136
02137 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02138 if (!vms_p) {
02139 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02140 }
02141
02142 if (!vms_p) {
02143 vms_p = create_vm_state_from_user(vmu);
02144 }
02145 ret = init_mailstream(vms_p, fold);
02146 if (!vms_p->mailstream) {
02147 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02148 return -1;
02149 }
02150 if (ret == 0) {
02151 ast_mutex_lock(&vms_p->lock);
02152 pgm = mail_newsearchpgm ();
02153 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02154 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02155 pgm->header = hdr;
02156 if (fold != OLD_FOLDER) {
02157 pgm->unseen = 1;
02158 pgm->seen = 0;
02159 }
02160
02161
02162
02163 else {
02164 pgm->unseen = 0;
02165 pgm->seen = 1;
02166 }
02167
02168 if (fold == NEW_FOLDER) {
02169 if (urgent) {
02170 pgm->flagged = 1;
02171 pgm->unflagged = 0;
02172 } else {
02173 pgm->flagged = 0;
02174 pgm->unflagged = 1;
02175 }
02176 }
02177 pgm->undeleted = 1;
02178 pgm->deleted = 0;
02179
02180 vms_p->vmArrayIndex = 0;
02181 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02182 if (fold == 0 && urgent == 0)
02183 vms_p->newmessages = vms_p->vmArrayIndex;
02184 if (fold == 1)
02185 vms_p->oldmessages = vms_p->vmArrayIndex;
02186 if (fold == 0 && urgent == 1)
02187 vms_p->urgentmessages = vms_p->vmArrayIndex;
02188
02189 mail_free_searchpgm(&pgm);
02190 ast_mutex_unlock(&vms_p->lock);
02191 vms_p->updated = 0;
02192 return vms_p->vmArrayIndex;
02193 } else {
02194 ast_mutex_lock(&vms_p->lock);
02195 mail_ping(vms_p->mailstream);
02196 ast_mutex_unlock(&vms_p->lock);
02197 }
02198 return 0;
02199 }
02200
02201 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02202 {
02203
02204 check_quota(vms, vmu->imapfolder);
02205 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02206 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02207 ast_play_and_wait(chan, "vm-mailboxfull");
02208 return -1;
02209 }
02210
02211
02212 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));
02213 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02214 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02215 ast_play_and_wait(chan, "vm-mailboxfull");
02216 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02217 return -1;
02218 }
02219
02220 return 0;
02221 }
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232 static int messagecount(const char *context, const char *mailbox, const char *folder)
02233 {
02234 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02235 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02236 } else {
02237 return __messagecount(context, mailbox, folder);
02238 }
02239 }
02240
02241 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)
02242 {
02243 char *myserveremail = serveremail;
02244 char fn[PATH_MAX];
02245 char introfn[PATH_MAX];
02246 char mailbox[256];
02247 char *stringp;
02248 FILE *p = NULL;
02249 char tmp[80] = "/tmp/astmail-XXXXXX";
02250 long len;
02251 void *buf;
02252 int tempcopy = 0;
02253 STRING str;
02254 int ret;
02255 char *imap_flags = NIL;
02256 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02257 int box = NEW_FOLDER;
02258
02259
02260 if (msgnum < 0) {
02261 if(!imapgreetings) {
02262 return 0;
02263 } else {
02264 box = GREETINGS_FOLDER;
02265 }
02266 }
02267
02268 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02269 return -1;
02270 }
02271
02272
02273 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02274 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02275 imap_flags = "\\FLAGGED";
02276 }
02277
02278
02279 fmt = ast_strdupa(fmt);
02280 stringp = fmt;
02281 strsep(&stringp, "|");
02282
02283 if (!ast_strlen_zero(vmu->serveremail))
02284 myserveremail = vmu->serveremail;
02285
02286 if (msgnum > -1)
02287 make_file(fn, sizeof(fn), dir, msgnum);
02288 else
02289 ast_copy_string (fn, dir, sizeof(fn));
02290
02291 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02292 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02293 *introfn = '\0';
02294 }
02295
02296 if (ast_strlen_zero(vmu->email)) {
02297
02298
02299
02300
02301
02302 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02303 tempcopy = 1;
02304 }
02305
02306 if (!strcmp(fmt, "wav49"))
02307 fmt = "WAV";
02308 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02309
02310
02311
02312 if (!(p = vm_mkftemp(tmp))) {
02313 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02314 if (tempcopy)
02315 *(vmu->email) = '\0';
02316 return -1;
02317 }
02318
02319 if (msgnum < 0 && imapgreetings) {
02320 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02321 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02322 return -1;
02323 }
02324 imap_delete_old_greeting(fn, vms);
02325 }
02326
02327 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02328 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02329 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02330 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02331
02332 len = ftell(p);
02333 rewind(p);
02334 if (!(buf = ast_malloc(len + 1))) {
02335 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02336 fclose(p);
02337 if (tempcopy)
02338 *(vmu->email) = '\0';
02339 return -1;
02340 }
02341 if (fread(buf, len, 1, p) < len) {
02342 if (ferror(p)) {
02343 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02344 return -1;
02345 }
02346 }
02347 ((char *) buf)[len] = '\0';
02348 INIT(&str, mail_string, buf, len);
02349 ret = init_mailstream(vms, box);
02350 if (ret == 0) {
02351 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02352 ast_mutex_lock(&vms->lock);
02353 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02354 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02355 ast_mutex_unlock(&vms->lock);
02356 fclose(p);
02357 unlink(tmp);
02358 ast_free(buf);
02359 } else {
02360 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02361 fclose(p);
02362 unlink(tmp);
02363 ast_free(buf);
02364 return -1;
02365 }
02366 ast_debug(3, "%s stored\n", fn);
02367
02368 if (tempcopy)
02369 *(vmu->email) = '\0';
02370 inprocess_count(vmu->mailbox, vmu->context, -1);
02371 return 0;
02372
02373 }
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386
02387
02388 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02389 {
02390 char tmp[PATH_MAX] = "";
02391 char *mailboxnc;
02392 char *context;
02393 char *mb;
02394 char *cur;
02395 if (newmsgs)
02396 *newmsgs = 0;
02397 if (oldmsgs)
02398 *oldmsgs = 0;
02399 if (urgentmsgs)
02400 *urgentmsgs = 0;
02401
02402 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02403
02404 if (ast_strlen_zero(mailbox_context))
02405 return 0;
02406
02407 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02408 context = strchr(tmp, '@');
02409 if (strchr(mailbox_context, ',')) {
02410 int tmpnew, tmpold, tmpurgent;
02411 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02412 mb = tmp;
02413 while ((cur = strsep(&mb, ", "))) {
02414 if (!ast_strlen_zero(cur)) {
02415 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02416 return -1;
02417 else {
02418 if (newmsgs)
02419 *newmsgs += tmpnew;
02420 if (oldmsgs)
02421 *oldmsgs += tmpold;
02422 if (urgentmsgs)
02423 *urgentmsgs += tmpurgent;
02424 }
02425 }
02426 }
02427 return 0;
02428 }
02429 if (context) {
02430 *context = '\0';
02431 mailboxnc = tmp;
02432 context++;
02433 } else {
02434 context = "default";
02435 mailboxnc = (char *) mailbox_context;
02436 }
02437
02438 if (newmsgs) {
02439 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02440 if (!vmu) {
02441 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02442 return -1;
02443 }
02444 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02445 free_user(vmu);
02446 return -1;
02447 }
02448 free_user(vmu);
02449 }
02450 if (oldmsgs) {
02451 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02452 return -1;
02453 }
02454 }
02455 if (urgentmsgs) {
02456 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02457 return -1;
02458 }
02459 }
02460 return 0;
02461 }
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473 static int has_voicemail(const char *mailbox, const char *folder)
02474 {
02475 char tmp[256], *tmp2, *box, *context;
02476 ast_copy_string(tmp, mailbox, sizeof(tmp));
02477 tmp2 = tmp;
02478 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02479 while ((box = strsep(&tmp2, ",&"))) {
02480 if (!ast_strlen_zero(box)) {
02481 if (has_voicemail(box, folder)) {
02482 return 1;
02483 }
02484 }
02485 }
02486 }
02487 if ((context = strchr(tmp, '@'))) {
02488 *context++ = '\0';
02489 } else {
02490 context = "default";
02491 }
02492 return __messagecount(context, tmp, folder) ? 1 : 0;
02493 }
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509
02510 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)
02511 {
02512 struct vm_state *sendvms = NULL, *destvms = NULL;
02513 char messagestring[10];
02514 if (msgnum >= recip->maxmsg) {
02515 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02516 return -1;
02517 }
02518 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02519 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02520 return -1;
02521 }
02522 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02523 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02524 return -1;
02525 }
02526 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02527 ast_mutex_lock(&sendvms->lock);
02528 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02529 ast_mutex_unlock(&sendvms->lock);
02530 return 0;
02531 }
02532 ast_mutex_unlock(&sendvms->lock);
02533 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02534 return -1;
02535 }
02536
02537 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02538 {
02539 char tmp[256], *t = tmp;
02540 size_t left = sizeof(tmp);
02541
02542 if (box == OLD_FOLDER) {
02543 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02544 } else {
02545 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02546 }
02547
02548 if (box == NEW_FOLDER) {
02549 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02550 } else {
02551 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02552 }
02553
02554
02555 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02556
02557
02558 if (!ast_strlen_zero(authuser))
02559 ast_build_string(&t, &left, "/authuser=%s", authuser);
02560
02561
02562 if (!ast_strlen_zero(imapflags))
02563 ast_build_string(&t, &left, "/%s", imapflags);
02564
02565
02566 #if 1
02567 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02568 #else
02569 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02570 #endif
02571 if (box == NEW_FOLDER || box == OLD_FOLDER)
02572 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02573 else if (box == GREETINGS_FOLDER)
02574 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02575 else {
02576 if (!ast_strlen_zero(imapparentfolder)) {
02577
02578 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02579 } else {
02580 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02581 }
02582 }
02583 }
02584
02585 static int init_mailstream(struct vm_state *vms, int box)
02586 {
02587 MAILSTREAM *stream = NIL;
02588 long debug;
02589 char tmp[256];
02590
02591 if (!vms) {
02592 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02593 return -1;
02594 }
02595 if (option_debug > 2)
02596 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02597 if (vms->mailstream == NIL || !vms->mailstream) {
02598 if (option_debug)
02599 ast_log(LOG_DEBUG, "mailstream not set.\n");
02600 } else {
02601 stream = vms->mailstream;
02602 }
02603
02604 debug = NIL;
02605
02606 if (delimiter == '\0') {
02607 char *cp;
02608 #ifdef USE_SYSTEM_IMAP
02609 #include <imap/linkage.c>
02610 #elif defined(USE_SYSTEM_CCLIENT)
02611 #include <c-client/linkage.c>
02612 #else
02613 #include "linkage.c"
02614 #endif
02615
02616 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02617 ast_mutex_lock(&vms->lock);
02618 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02619 ast_mutex_unlock(&vms->lock);
02620 if (stream == NIL) {
02621 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02622 return -1;
02623 }
02624 get_mailbox_delimiter(stream);
02625
02626 for (cp = vms->imapfolder; *cp; cp++)
02627 if (*cp == '/')
02628 *cp = delimiter;
02629 }
02630
02631 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02632 if (option_debug > 2)
02633 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02634 ast_mutex_lock(&vms->lock);
02635 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02636 ast_mutex_unlock(&vms->lock);
02637 if (vms->mailstream == NIL) {
02638 return -1;
02639 } else {
02640 return 0;
02641 }
02642 }
02643
02644 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02645 {
02646 SEARCHPGM *pgm;
02647 SEARCHHEADER *hdr;
02648 int ret, urgent = 0;
02649
02650
02651 if (box == 11) {
02652 box = NEW_FOLDER;
02653 urgent = 1;
02654 }
02655
02656 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02657 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02658 vms->imapversion = vmu->imapversion;
02659 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02660
02661 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02662 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02663 return -1;
02664 }
02665
02666 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02667
02668
02669 if (box == 0) {
02670 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02671 check_quota(vms, (char *) mbox(vmu, box));
02672 }
02673
02674 ast_mutex_lock(&vms->lock);
02675 pgm = mail_newsearchpgm();
02676
02677
02678 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02679 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02680 pgm->header = hdr;
02681 pgm->deleted = 0;
02682 pgm->undeleted = 1;
02683
02684
02685 if (box == NEW_FOLDER && urgent == 1) {
02686 pgm->unseen = 1;
02687 pgm->seen = 0;
02688 pgm->flagged = 1;
02689 pgm->unflagged = 0;
02690 } else if (box == NEW_FOLDER && urgent == 0) {
02691 pgm->unseen = 1;
02692 pgm->seen = 0;
02693 pgm->flagged = 0;
02694 pgm->unflagged = 1;
02695 } else if (box == OLD_FOLDER) {
02696 pgm->seen = 1;
02697 pgm->unseen = 0;
02698 }
02699
02700 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02701
02702 vms->vmArrayIndex = 0;
02703 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02704 vms->lastmsg = vms->vmArrayIndex - 1;
02705 mail_free_searchpgm(&pgm);
02706
02707
02708
02709
02710 if (box == 0 && !vms->dh_arraysize) {
02711 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02712 }
02713 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02714 ast_mutex_unlock(&vms->lock);
02715 return -1;
02716 }
02717
02718 ast_mutex_unlock(&vms->lock);
02719 return 0;
02720 }
02721
02722 static void write_file(char *filename, char *buffer, unsigned long len)
02723 {
02724 FILE *output;
02725
02726 output = fopen (filename, "w");
02727 if (fwrite(buffer, len, 1, output) != 1) {
02728 if (ferror(output)) {
02729 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02730 }
02731 }
02732 fclose (output);
02733 }
02734
02735 static void update_messages_by_imapuser(const char *user, unsigned long number)
02736 {
02737 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02738
02739 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02740 return;
02741 }
02742
02743 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02744
02745
02746 if (vms->vmArrayIndex >= vms->msg_array_max) {
02747 long *new_mem = ast_realloc(vms->msgArray, 2 * vms->msg_array_max * sizeof(long));
02748 if (!new_mem) {
02749 return;
02750 }
02751 vms->msgArray = new_mem;
02752 vms->msg_array_max *= 2;
02753 }
02754
02755 vms->msgArray[vms->vmArrayIndex++] = number;
02756 }
02757
02758 void mm_searched(MAILSTREAM *stream, unsigned long number)
02759 {
02760 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02761
02762 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02763 return;
02764
02765 update_messages_by_imapuser(user, number);
02766 }
02767
02768 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02769 {
02770 struct ast_variable *var;
02771 struct ast_vm_user *vmu;
02772
02773 vmu = ast_calloc(1, sizeof *vmu);
02774 if (!vmu)
02775 return NULL;
02776
02777 populate_defaults(vmu);
02778 ast_set_flag(vmu, VM_ALLOCED);
02779
02780 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02781 if (var) {
02782 apply_options_full(vmu, var);
02783 ast_variables_destroy(var);
02784 return vmu;
02785 } else {
02786 ast_free(vmu);
02787 return NULL;
02788 }
02789 }
02790
02791
02792
02793 void mm_exists(MAILSTREAM * stream, unsigned long number)
02794 {
02795
02796 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02797 if (number == 0) return;
02798 set_update(stream);
02799 }
02800
02801
02802 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02803 {
02804
02805 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02806 if (number == 0) return;
02807 set_update(stream);
02808 }
02809
02810
02811 void mm_flags(MAILSTREAM * stream, unsigned long number)
02812 {
02813
02814 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02815 if (number == 0) return;
02816 set_update(stream);
02817 }
02818
02819
02820 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02821 {
02822 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02823 mm_log (string, errflg);
02824 }
02825
02826
02827 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02828 {
02829 if (delimiter == '\0') {
02830 delimiter = delim;
02831 }
02832
02833 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02834 if (attributes & LATT_NOINFERIORS)
02835 ast_debug(5, "no inferiors\n");
02836 if (attributes & LATT_NOSELECT)
02837 ast_debug(5, "no select\n");
02838 if (attributes & LATT_MARKED)
02839 ast_debug(5, "marked\n");
02840 if (attributes & LATT_UNMARKED)
02841 ast_debug(5, "unmarked\n");
02842 }
02843
02844
02845 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02846 {
02847 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02848 if (attributes & LATT_NOINFERIORS)
02849 ast_debug(5, "no inferiors\n");
02850 if (attributes & LATT_NOSELECT)
02851 ast_debug(5, "no select\n");
02852 if (attributes & LATT_MARKED)
02853 ast_debug(5, "marked\n");
02854 if (attributes & LATT_UNMARKED)
02855 ast_debug(5, "unmarked\n");
02856 }
02857
02858
02859 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02860 {
02861 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02862 if (status->flags & SA_MESSAGES)
02863 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02864 if (status->flags & SA_RECENT)
02865 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02866 if (status->flags & SA_UNSEEN)
02867 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02868 if (status->flags & SA_UIDVALIDITY)
02869 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02870 if (status->flags & SA_UIDNEXT)
02871 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02872 ast_log(AST_LOG_NOTICE, "\n");
02873 }
02874
02875
02876 void mm_log(char *string, long errflg)
02877 {
02878 switch ((short) errflg) {
02879 case NIL:
02880 ast_debug(1, "IMAP Info: %s\n", string);
02881 break;
02882 case PARSE:
02883 case WARN:
02884 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02885 break;
02886 case ERROR:
02887 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02888 break;
02889 }
02890 }
02891
02892
02893 void mm_dlog(char *string)
02894 {
02895 ast_log(AST_LOG_NOTICE, "%s\n", string);
02896 }
02897
02898
02899 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02900 {
02901 struct ast_vm_user *vmu;
02902
02903 ast_debug(4, "Entering callback mm_login\n");
02904
02905 ast_copy_string(user, mb->user, MAILTMPLEN);
02906
02907
02908 if (!ast_strlen_zero(authpassword)) {
02909 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02910 } else {
02911 AST_LIST_TRAVERSE(&users, vmu, list) {
02912 if (!strcasecmp(mb->user, vmu->imapuser)) {
02913 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02914 break;
02915 }
02916 }
02917 if (!vmu) {
02918 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02919 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02920 free_user(vmu);
02921 }
02922 }
02923 }
02924 }
02925
02926
02927 void mm_critical(MAILSTREAM * stream)
02928 {
02929 }
02930
02931
02932 void mm_nocritical(MAILSTREAM * stream)
02933 {
02934 }
02935
02936
02937 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02938 {
02939 kill (getpid (), SIGSTOP);
02940 return NIL;
02941 }
02942
02943
02944 void mm_fatal(char *string)
02945 {
02946 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02947 }
02948
02949
02950 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02951 {
02952 struct vm_state *vms;
02953 char *mailbox = stream->mailbox, *user;
02954 char buf[1024] = "";
02955 unsigned long usage = 0, limit = 0;
02956
02957 while (pquota) {
02958 usage = pquota->usage;
02959 limit = pquota->limit;
02960 pquota = pquota->next;
02961 }
02962
02963 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)))) {
02964 ast_log(AST_LOG_ERROR, "No state found.\n");
02965 return;
02966 }
02967
02968 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02969
02970 vms->quota_usage = usage;
02971 vms->quota_limit = limit;
02972 }
02973
02974 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02975 {
02976 char *start, *eol_pnt;
02977 int taglen;
02978
02979 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02980 return NULL;
02981
02982 taglen = strlen(tag) + 1;
02983 if (taglen < 1)
02984 return NULL;
02985
02986 if (!(start = strstr(header, tag)))
02987 return NULL;
02988
02989
02990 memset(buf, 0, len);
02991
02992 ast_copy_string(buf, start+taglen, len);
02993 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02994 *eol_pnt = '\0';
02995 return buf;
02996 }
02997
02998 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02999 {
03000 char *start, *quote, *eol_pnt;
03001
03002 if (ast_strlen_zero(mailbox))
03003 return NULL;
03004
03005 if (!(start = strstr(mailbox, "/user=")))
03006 return NULL;
03007
03008 ast_copy_string(buf, start+6, len);
03009
03010 if (!(quote = strchr(buf, '\"'))) {
03011 if (!(eol_pnt = strchr(buf, '/')))
03012 eol_pnt = strchr(buf,'}');
03013 *eol_pnt = '\0';
03014 return buf;
03015 } else {
03016 eol_pnt = strchr(buf+1,'\"');
03017 *eol_pnt = '\0';
03018 return buf+1;
03019 }
03020 }
03021
03022 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
03023 {
03024 struct vm_state *vms_p;
03025
03026 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03027 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
03028 return vms_p;
03029 }
03030 if (option_debug > 4)
03031 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
03032
03033 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
03034 return NULL;
03035 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
03036 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
03037 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03038 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03039 vms_p->mailstream = NIL;
03040 vms_p->imapversion = vmu->imapversion;
03041 if (option_debug > 4)
03042 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03043 vms_p->updated = 1;
03044
03045 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03046 init_vm_state(vms_p);
03047 vmstate_insert(vms_p);
03048 return vms_p;
03049 }
03050
03051 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03052 {
03053 struct vmstate *vlist = NULL;
03054
03055 if (interactive) {
03056 struct vm_state *vms;
03057 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03058 vms = pthread_getspecific(ts_vmstate.key);
03059 return vms;
03060 }
03061
03062 AST_LIST_LOCK(&vmstates);
03063 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03064 if (!vlist->vms) {
03065 ast_debug(3, "error: vms is NULL for %s\n", user);
03066 continue;
03067 }
03068 if (vlist->vms->imapversion != imapversion) {
03069 continue;
03070 }
03071 if (!vlist->vms->imapuser) {
03072 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03073 continue;
03074 }
03075
03076 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03077 AST_LIST_UNLOCK(&vmstates);
03078 return vlist->vms;
03079 }
03080 }
03081 AST_LIST_UNLOCK(&vmstates);
03082
03083 ast_debug(3, "%s not found in vmstates\n", user);
03084
03085 return NULL;
03086 }
03087
03088 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03089 {
03090
03091 struct vmstate *vlist = NULL;
03092 const char *local_context = S_OR(context, "default");
03093
03094 if (interactive) {
03095 struct vm_state *vms;
03096 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03097 vms = pthread_getspecific(ts_vmstate.key);
03098 return vms;
03099 }
03100
03101 AST_LIST_LOCK(&vmstates);
03102 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03103 if (!vlist->vms) {
03104 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03105 continue;
03106 }
03107 if (vlist->vms->imapversion != imapversion) {
03108 continue;
03109 }
03110 if (!vlist->vms->username || !vlist->vms->context) {
03111 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03112 continue;
03113 }
03114
03115 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);
03116
03117 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03118 ast_debug(3, "Found it!\n");
03119 AST_LIST_UNLOCK(&vmstates);
03120 return vlist->vms;
03121 }
03122 }
03123 AST_LIST_UNLOCK(&vmstates);
03124
03125 ast_debug(3, "%s not found in vmstates\n", mailbox);
03126
03127 return NULL;
03128 }
03129
03130 static void vmstate_insert(struct vm_state *vms)
03131 {
03132 struct vmstate *v;
03133 struct vm_state *altvms;
03134
03135
03136
03137
03138 if (vms->interactive == 1) {
03139 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03140 if (altvms) {
03141 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03142 vms->newmessages = altvms->newmessages;
03143 vms->oldmessages = altvms->oldmessages;
03144 vms->vmArrayIndex = altvms->vmArrayIndex;
03145
03146 vms->lastmsg = altvms->lastmsg;
03147 vms->curmsg = altvms->curmsg;
03148
03149 vms->persist_vms = altvms;
03150
03151 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03152 vms->mailstream = altvms->mailstream;
03153 #else
03154 vms->mailstream = NIL;
03155 #endif
03156 }
03157 return;
03158 }
03159
03160 if (!(v = ast_calloc(1, sizeof(*v))))
03161 return;
03162
03163 v->vms = vms;
03164
03165 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03166
03167 AST_LIST_LOCK(&vmstates);
03168 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03169 AST_LIST_UNLOCK(&vmstates);
03170 }
03171
03172 static void vmstate_delete(struct vm_state *vms)
03173 {
03174 struct vmstate *vc = NULL;
03175 struct vm_state *altvms = NULL;
03176
03177
03178
03179 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03180 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03181 altvms->newmessages = vms->newmessages;
03182 altvms->oldmessages = vms->oldmessages;
03183 altvms->updated = 1;
03184 vms->mailstream = mail_close(vms->mailstream);
03185
03186
03187 return;
03188 }
03189
03190 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03191
03192 AST_LIST_LOCK(&vmstates);
03193 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03194 if (vc->vms == vms) {
03195 AST_LIST_REMOVE_CURRENT(list);
03196 break;
03197 }
03198 }
03199 AST_LIST_TRAVERSE_SAFE_END
03200 AST_LIST_UNLOCK(&vmstates);
03201
03202 if (vc) {
03203 ast_mutex_destroy(&vc->vms->lock);
03204 ast_free(vc->vms->msgArray);
03205 vc->vms->msgArray = NULL;
03206 vc->vms->msg_array_max = 0;
03207
03208 ast_free(vc);
03209 } else {
03210 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03211 }
03212 }
03213
03214 static void set_update(MAILSTREAM * stream)
03215 {
03216 struct vm_state *vms;
03217 char *mailbox = stream->mailbox, *user;
03218 char buf[1024] = "";
03219
03220 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03221 if (user && option_debug > 2)
03222 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03223 return;
03224 }
03225
03226 ast_debug(3, "User %s mailbox set for update.\n", user);
03227
03228 vms->updated = 1;
03229 }
03230
03231 static void init_vm_state(struct vm_state *vms)
03232 {
03233 vms->msg_array_max = VMSTATE_MAX_MSG_ARRAY;
03234 vms->msgArray = ast_calloc(vms->msg_array_max, sizeof(long));
03235 if (!vms->msgArray) {
03236
03237 vms->msg_array_max = 0;
03238 }
03239 vms->vmArrayIndex = 0;
03240 ast_mutex_init(&vms->lock);
03241 }
03242
03243 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03244 {
03245 char *body_content;
03246 char *body_decoded;
03247 char *fn = is_intro ? vms->introfn : vms->fn;
03248 unsigned long len;
03249 unsigned long newlen;
03250 char filename[256];
03251
03252 if (!body || body == NIL)
03253 return -1;
03254
03255 ast_mutex_lock(&vms->lock);
03256 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03257 ast_mutex_unlock(&vms->lock);
03258 if (body_content != NIL) {
03259 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03260
03261 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03262
03263 if (!newlen) {
03264 return -1;
03265 }
03266 write_file(filename, (char *) body_decoded, newlen);
03267 } else {
03268 ast_debug(5, "Body of message is NULL.\n");
03269 return -1;
03270 }
03271 return 0;
03272 }
03273
03274
03275
03276
03277
03278
03279
03280
03281 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03282 char tmp[50];
03283 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03284 mail_list(stream, tmp, "*");
03285 }
03286
03287
03288
03289
03290
03291
03292
03293
03294 static void check_quota(struct vm_state *vms, char *mailbox) {
03295 ast_mutex_lock(&vms->lock);
03296 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03297 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03298 if (vms && vms->mailstream != NULL) {
03299 imap_getquotaroot(vms->mailstream, mailbox);
03300 } else {
03301 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03302 }
03303 ast_mutex_unlock(&vms->lock);
03304 }
03305
03306 #endif
03307
03308
03309
03310
03311
03312 static int vm_lock_path(const char *path)
03313 {
03314 switch (ast_lock_path(path)) {
03315 case AST_LOCK_TIMEOUT:
03316 return -1;
03317 default:
03318 return 0;
03319 }
03320 }
03321
03322
03323 #ifdef ODBC_STORAGE
03324 struct generic_prepare_struct {
03325 char *sql;
03326 int argc;
03327 char **argv;
03328 };
03329
03330 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03331 {
03332 struct generic_prepare_struct *gps = data;
03333 int res, i;
03334 SQLHSTMT stmt;
03335
03336 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03337 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03338 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03339 return NULL;
03340 }
03341 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03342 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03343 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03344 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03345 return NULL;
03346 }
03347 for (i = 0; i < gps->argc; i++)
03348 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03349
03350 return stmt;
03351 }
03352
03353
03354
03355
03356
03357
03358
03359
03360
03361
03362
03363
03364
03365
03366
03367 static int retrieve_file(char *dir, int msgnum)
03368 {
03369 int x = 0;
03370 int res;
03371 int fd = -1;
03372 size_t fdlen = 0;
03373 void *fdm = MAP_FAILED;
03374 SQLSMALLINT colcount = 0;
03375 SQLHSTMT stmt;
03376 char sql[PATH_MAX];
03377 char fmt[80]="";
03378 char *c;
03379 char coltitle[256];
03380 SQLSMALLINT collen;
03381 SQLSMALLINT datatype;
03382 SQLSMALLINT decimaldigits;
03383 SQLSMALLINT nullable;
03384 SQLULEN colsize;
03385 SQLLEN colsize2;
03386 FILE *f = NULL;
03387 char rowdata[80];
03388 char fn[PATH_MAX];
03389 char full_fn[PATH_MAX];
03390 char msgnums[80];
03391 char *argv[] = { dir, msgnums };
03392 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03393
03394 struct odbc_obj *obj;
03395 obj = ast_odbc_request_obj(odbc_database, 0);
03396 if (obj) {
03397 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03398 c = strchr(fmt, '|');
03399 if (c)
03400 *c = '\0';
03401 if (!strcasecmp(fmt, "wav49"))
03402 strcpy(fmt, "WAV");
03403 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03404 if (msgnum > -1)
03405 make_file(fn, sizeof(fn), dir, msgnum);
03406 else
03407 ast_copy_string(fn, dir, sizeof(fn));
03408
03409
03410 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03411
03412 if (!(f = fopen(full_fn, "w+"))) {
03413 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03414 goto yuck;
03415 }
03416
03417 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03418 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03419 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03420 if (!stmt) {
03421 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03422 ast_odbc_release_obj(obj);
03423 goto yuck;
03424 }
03425 res = SQLFetch(stmt);
03426 if (res == SQL_NO_DATA) {
03427 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03428 ast_odbc_release_obj(obj);
03429 goto yuck;
03430 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03431 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03432 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03433 ast_odbc_release_obj(obj);
03434 goto yuck;
03435 }
03436 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03437 if (fd < 0) {
03438 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03439 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03440 ast_odbc_release_obj(obj);
03441 goto yuck;
03442 }
03443 res = SQLNumResultCols(stmt, &colcount);
03444 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03445 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03446 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03447 ast_odbc_release_obj(obj);
03448 goto yuck;
03449 }
03450 if (f)
03451 fprintf(f, "[message]\n");
03452 for (x = 0; x < colcount; x++) {
03453 rowdata[0] = '\0';
03454 colsize = 0;
03455 collen = sizeof(coltitle);
03456 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03457 &datatype, &colsize, &decimaldigits, &nullable);
03458 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03459 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03460 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03461 ast_odbc_release_obj(obj);
03462 goto yuck;
03463 }
03464 if (!strcasecmp(coltitle, "recording")) {
03465 off_t offset;
03466 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03467 fdlen = colsize2;
03468 if (fd > -1) {
03469 char tmp[1]="";
03470 lseek(fd, fdlen - 1, SEEK_SET);
03471 if (write(fd, tmp, 1) != 1) {
03472 close(fd);
03473 fd = -1;
03474 continue;
03475 }
03476
03477 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03478 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03479 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03480 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03481 ast_odbc_release_obj(obj);
03482 goto yuck;
03483 } else {
03484 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03485 munmap(fdm, CHUNKSIZE);
03486 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03487 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03488 unlink(full_fn);
03489 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03490 ast_odbc_release_obj(obj);
03491 goto yuck;
03492 }
03493 }
03494 }
03495 if (truncate(full_fn, fdlen) < 0) {
03496 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03497 }
03498 }
03499 } else {
03500 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03501 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03502 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03503 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03504 ast_odbc_release_obj(obj);
03505 goto yuck;
03506 }
03507 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03508 fprintf(f, "%s=%s\n", coltitle, rowdata);
03509 }
03510 }
03511 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03512 ast_odbc_release_obj(obj);
03513 } else
03514 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03515 yuck:
03516 if (f)
03517 fclose(f);
03518 if (fd > -1)
03519 close(fd);
03520 return x - 1;
03521 }
03522
03523
03524
03525
03526
03527
03528
03529
03530
03531
03532
03533
03534 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03535 {
03536 int x = 0;
03537 int res;
03538 SQLHSTMT stmt;
03539 char sql[PATH_MAX];
03540 char rowdata[20];
03541 char *argv[] = { dir };
03542 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03543
03544 struct odbc_obj *obj;
03545 obj = ast_odbc_request_obj(odbc_database, 0);
03546 if (obj) {
03547 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03548
03549 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03550 if (!stmt) {
03551 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03552 ast_odbc_release_obj(obj);
03553 goto yuck;
03554 }
03555 res = SQLFetch(stmt);
03556 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03557 if (res == SQL_NO_DATA) {
03558 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03559 } else {
03560 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03561 }
03562
03563 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03564 ast_odbc_release_obj(obj);
03565 goto yuck;
03566 }
03567 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03568 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03569 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03570 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03571 ast_odbc_release_obj(obj);
03572 goto yuck;
03573 }
03574 if (sscanf(rowdata, "%30d", &x) != 1)
03575 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03576 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03577 ast_odbc_release_obj(obj);
03578 return x;
03579 } else
03580 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03581 yuck:
03582 return x - 1;
03583 }
03584
03585
03586
03587
03588
03589
03590
03591
03592
03593
03594 static int message_exists(char *dir, int msgnum)
03595 {
03596 int x = 0;
03597 int res;
03598 SQLHSTMT stmt;
03599 char sql[PATH_MAX];
03600 char rowdata[20];
03601 char msgnums[20];
03602 char *argv[] = { dir, msgnums };
03603 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03604
03605 struct odbc_obj *obj;
03606 obj = ast_odbc_request_obj(odbc_database, 0);
03607 if (obj) {
03608 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03609 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03610 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03611 if (!stmt) {
03612 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03613 ast_odbc_release_obj(obj);
03614 goto yuck;
03615 }
03616 res = SQLFetch(stmt);
03617 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03618 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03619 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03620 ast_odbc_release_obj(obj);
03621 goto yuck;
03622 }
03623 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03624 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03625 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03626 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03627 ast_odbc_release_obj(obj);
03628 goto yuck;
03629 }
03630 if (sscanf(rowdata, "%30d", &x) != 1)
03631 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03632 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03633 ast_odbc_release_obj(obj);
03634 } else
03635 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03636 yuck:
03637 return x;
03638 }
03639
03640
03641
03642
03643
03644
03645
03646
03647
03648
03649 static int count_messages(struct ast_vm_user *vmu, char *dir)
03650 {
03651 int x = 0;
03652 int res;
03653 SQLHSTMT stmt;
03654 char sql[PATH_MAX];
03655 char rowdata[20];
03656 char *argv[] = { dir };
03657 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03658
03659 struct odbc_obj *obj;
03660 obj = ast_odbc_request_obj(odbc_database, 0);
03661 if (obj) {
03662 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03663 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03664 if (!stmt) {
03665 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03666 ast_odbc_release_obj(obj);
03667 goto yuck;
03668 }
03669 res = SQLFetch(stmt);
03670 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03671 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03672 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03673 ast_odbc_release_obj(obj);
03674 goto yuck;
03675 }
03676 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03677 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03678 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03679 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03680 ast_odbc_release_obj(obj);
03681 goto yuck;
03682 }
03683 if (sscanf(rowdata, "%30d", &x) != 1)
03684 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03685 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03686 ast_odbc_release_obj(obj);
03687 return x;
03688 } else
03689 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03690 yuck:
03691 return x - 1;
03692
03693 }
03694
03695
03696
03697
03698
03699
03700
03701
03702
03703
03704
03705 static void delete_file(const char *sdir, int smsg)
03706 {
03707 SQLHSTMT stmt;
03708 char sql[PATH_MAX];
03709 char msgnums[20];
03710 char *argv[] = { NULL, msgnums };
03711 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03712 struct odbc_obj *obj;
03713
03714 argv[0] = ast_strdupa(sdir);
03715
03716 obj = ast_odbc_request_obj(odbc_database, 0);
03717 if (obj) {
03718 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03719 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03720 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03721 if (!stmt)
03722 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03723 else
03724 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03725 ast_odbc_release_obj(obj);
03726 } else
03727 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03728 return;
03729 }
03730
03731
03732
03733
03734
03735
03736
03737
03738
03739
03740
03741
03742 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03743 {
03744 SQLHSTMT stmt;
03745 char sql[512];
03746 char msgnums[20];
03747 char msgnumd[20];
03748 struct odbc_obj *obj;
03749 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03750 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03751
03752 delete_file(ddir, dmsg);
03753 obj = ast_odbc_request_obj(odbc_database, 0);
03754 if (obj) {
03755 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03756 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03757 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);
03758 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03759 if (!stmt)
03760 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03761 else
03762 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03763 ast_odbc_release_obj(obj);
03764 } else
03765 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03766 return;
03767 }
03768
03769 struct insert_data {
03770 char *sql;
03771 const char *dir;
03772 const char *msgnums;
03773 void *data;
03774 SQLLEN datalen;
03775 SQLLEN indlen;
03776 const char *context;
03777 const char *macrocontext;
03778 const char *callerid;
03779 const char *origtime;
03780 const char *duration;
03781 const char *mailboxuser;
03782 const char *mailboxcontext;
03783 const char *category;
03784 const char *flag;
03785 };
03786
03787 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03788 {
03789 struct insert_data *data = vdata;
03790 int res;
03791 SQLHSTMT stmt;
03792
03793 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03794 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03795 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03796 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03797 return NULL;
03798 }
03799
03800 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03801 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03802 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03803 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03804 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03805 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03806 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03807 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03808 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03809 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03810 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03811 if (!ast_strlen_zero(data->category)) {
03812 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03813 }
03814 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03815 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03816 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03817 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03818 return NULL;
03819 }
03820
03821 return stmt;
03822 }
03823
03824
03825
03826
03827
03828
03829
03830
03831
03832
03833
03834
03835
03836
03837 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03838 {
03839 int res = 0;
03840 int fd = -1;
03841 void *fdm = MAP_FAILED;
03842 off_t fdlen = -1;
03843 SQLHSTMT stmt;
03844 char sql[PATH_MAX];
03845 char msgnums[20];
03846 char fn[PATH_MAX];
03847 char full_fn[PATH_MAX];
03848 char fmt[80]="";
03849 char *c;
03850 struct ast_config *cfg = NULL;
03851 struct odbc_obj *obj;
03852 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03853 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03854 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03855
03856 delete_file(dir, msgnum);
03857 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03858 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03859 return -1;
03860 }
03861
03862 do {
03863 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03864 c = strchr(fmt, '|');
03865 if (c)
03866 *c = '\0';
03867 if (!strcasecmp(fmt, "wav49"))
03868 strcpy(fmt, "WAV");
03869 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03870 if (msgnum > -1)
03871 make_file(fn, sizeof(fn), dir, msgnum);
03872 else
03873 ast_copy_string(fn, dir, sizeof(fn));
03874 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03875 cfg = ast_config_load(full_fn, config_flags);
03876 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03877 fd = open(full_fn, O_RDWR);
03878 if (fd < 0) {
03879 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03880 res = -1;
03881 break;
03882 }
03883 if (valid_config(cfg)) {
03884 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03885 idata.context = "";
03886 }
03887 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03888 idata.macrocontext = "";
03889 }
03890 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03891 idata.callerid = "";
03892 }
03893 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03894 idata.origtime = "";
03895 }
03896 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03897 idata.duration = "";
03898 }
03899 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03900 idata.category = "";
03901 }
03902 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03903 idata.flag = "";
03904 }
03905 }
03906 fdlen = lseek(fd, 0, SEEK_END);
03907 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03908 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03909 res = -1;
03910 break;
03911 }
03912 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03913 if (fdm == MAP_FAILED) {
03914 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03915 res = -1;
03916 break;
03917 }
03918 idata.data = fdm;
03919 idata.datalen = idata.indlen = fdlen;
03920
03921 if (!ast_strlen_zero(idata.category))
03922 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03923 else
03924 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03925
03926 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03927 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03928 } else {
03929 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03930 res = -1;
03931 }
03932 } while (0);
03933 if (obj) {
03934 ast_odbc_release_obj(obj);
03935 }
03936 if (valid_config(cfg))
03937 ast_config_destroy(cfg);
03938 if (fdm != MAP_FAILED)
03939 munmap(fdm, fdlen);
03940 if (fd > -1)
03941 close(fd);
03942 return res;
03943 }
03944
03945
03946
03947
03948
03949
03950
03951
03952
03953
03954
03955
03956
03957
03958 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03959 {
03960 SQLHSTMT stmt;
03961 char sql[PATH_MAX];
03962 char msgnums[20];
03963 char msgnumd[20];
03964 struct odbc_obj *obj;
03965 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03966 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03967
03968 delete_file(ddir, dmsg);
03969 obj = ast_odbc_request_obj(odbc_database, 0);
03970 if (obj) {
03971 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03972 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03973 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03974 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03975 if (!stmt)
03976 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03977 else
03978 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03979 ast_odbc_release_obj(obj);
03980 } else
03981 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03982 return;
03983 }
03984
03985
03986
03987
03988
03989
03990
03991
03992
03993
03994
03995
03996 static int remove_file(char *dir, int msgnum)
03997 {
03998 char fn[PATH_MAX];
03999 char full_fn[PATH_MAX];
04000 char msgnums[80];
04001
04002 if (msgnum > -1) {
04003 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
04004 make_file(fn, sizeof(fn), dir, msgnum);
04005 } else
04006 ast_copy_string(fn, dir, sizeof(fn));
04007 ast_filedelete(fn, NULL);
04008 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
04009 unlink(full_fn);
04010 return 0;
04011 }
04012 #else
04013 #ifndef IMAP_STORAGE
04014
04015
04016
04017
04018
04019
04020
04021
04022
04023 static int count_messages(struct ast_vm_user *vmu, char *dir)
04024 {
04025
04026 int vmcount = 0;
04027 DIR *vmdir = NULL;
04028 struct dirent *vment = NULL;
04029
04030 if (vm_lock_path(dir))
04031 return ERROR_LOCK_PATH;
04032
04033 if ((vmdir = opendir(dir))) {
04034 while ((vment = readdir(vmdir))) {
04035 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
04036 vmcount++;
04037 }
04038 }
04039 closedir(vmdir);
04040 }
04041 ast_unlock_path(dir);
04042
04043 return vmcount;
04044 }
04045
04046
04047
04048
04049
04050
04051
04052
04053 static void rename_file(char *sfn, char *dfn)
04054 {
04055 char stxt[PATH_MAX];
04056 char dtxt[PATH_MAX];
04057 ast_filerename(sfn, dfn, NULL);
04058 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04059 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04060 if (ast_check_realtime("voicemail_data")) {
04061 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04062 }
04063 rename(stxt, dtxt);
04064 }
04065
04066
04067
04068
04069
04070
04071
04072
04073
04074
04075
04076
04077 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04078 {
04079 int x;
04080 unsigned char map[MAXMSGLIMIT] = "";
04081 DIR *msgdir;
04082 struct dirent *msgdirent;
04083 int msgdirint;
04084 char extension[4];
04085 int stopcount = 0;
04086
04087
04088
04089
04090
04091 if (!(msgdir = opendir(dir))) {
04092 return -1;
04093 }
04094
04095 while ((msgdirent = readdir(msgdir))) {
04096 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04097 map[msgdirint] = 1;
04098 stopcount++;
04099 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04100 }
04101 }
04102 closedir(msgdir);
04103
04104 for (x = 0; x < vmu->maxmsg; x++) {
04105 if (map[x] == 1) {
04106 stopcount--;
04107 } else if (map[x] == 0 && !stopcount) {
04108 break;
04109 }
04110 }
04111
04112 return x - 1;
04113 }
04114
04115 #endif
04116 #endif
04117 #ifndef IMAP_STORAGE
04118
04119
04120
04121
04122
04123
04124
04125
04126
04127
04128 static int copy(char *infile, char *outfile)
04129 {
04130 int ifd;
04131 int ofd;
04132 int res;
04133 int len;
04134 char buf[4096];
04135
04136 #ifdef HARDLINK_WHEN_POSSIBLE
04137
04138 if (link(infile, outfile)) {
04139 #endif
04140 if ((ifd = open(infile, O_RDONLY)) < 0) {
04141 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04142 return -1;
04143 }
04144 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04145 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04146 close(ifd);
04147 return -1;
04148 }
04149 do {
04150 len = read(ifd, buf, sizeof(buf));
04151 if (len < 0) {
04152 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04153 close(ifd);
04154 close(ofd);
04155 unlink(outfile);
04156 } else if (len) {
04157 res = write(ofd, buf, len);
04158 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04159 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04160 close(ifd);
04161 close(ofd);
04162 unlink(outfile);
04163 }
04164 }
04165 } while (len);
04166 close(ifd);
04167 close(ofd);
04168 return 0;
04169 #ifdef HARDLINK_WHEN_POSSIBLE
04170 } else {
04171
04172 return 0;
04173 }
04174 #endif
04175 }
04176
04177
04178
04179
04180
04181
04182
04183
04184
04185
04186 static void copy_plain_file(char *frompath, char *topath)
04187 {
04188 char frompath2[PATH_MAX], topath2[PATH_MAX];
04189 struct ast_variable *tmp,*var = NULL;
04190 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04191 ast_filecopy(frompath, topath, NULL);
04192 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04193 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04194 if (ast_check_realtime("voicemail_data")) {
04195 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04196
04197 for (tmp = var; tmp; tmp = tmp->next) {
04198 if (!strcasecmp(tmp->name, "origmailbox")) {
04199 origmailbox = tmp->value;
04200 } else if (!strcasecmp(tmp->name, "context")) {
04201 context = tmp->value;
04202 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04203 macrocontext = tmp->value;
04204 } else if (!strcasecmp(tmp->name, "exten")) {
04205 exten = tmp->value;
04206 } else if (!strcasecmp(tmp->name, "priority")) {
04207 priority = tmp->value;
04208 } else if (!strcasecmp(tmp->name, "callerchan")) {
04209 callerchan = tmp->value;
04210 } else if (!strcasecmp(tmp->name, "callerid")) {
04211 callerid = tmp->value;
04212 } else if (!strcasecmp(tmp->name, "origdate")) {
04213 origdate = tmp->value;
04214 } else if (!strcasecmp(tmp->name, "origtime")) {
04215 origtime = tmp->value;
04216 } else if (!strcasecmp(tmp->name, "category")) {
04217 category = tmp->value;
04218 } else if (!strcasecmp(tmp->name, "duration")) {
04219 duration = tmp->value;
04220 }
04221 }
04222 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);
04223 }
04224 copy(frompath2, topath2);
04225 ast_variables_destroy(var);
04226 }
04227 #endif
04228
04229
04230
04231
04232
04233
04234
04235
04236
04237 static int vm_delete(char *file)
04238 {
04239 char *txt;
04240 int txtsize = 0;
04241
04242 txtsize = (strlen(file) + 5)*sizeof(char);
04243 txt = ast_alloca(txtsize);
04244
04245
04246
04247 if (ast_check_realtime("voicemail_data")) {
04248 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04249 }
04250 snprintf(txt, txtsize, "%s.txt", file);
04251 unlink(txt);
04252 return ast_filedelete(file, NULL);
04253 }
04254
04255
04256
04257
04258 static int inbuf(struct baseio *bio, FILE *fi)
04259 {
04260 int l;
04261
04262 if (bio->ateof)
04263 return 0;
04264
04265 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04266 if (ferror(fi))
04267 return -1;
04268
04269 bio->ateof = 1;
04270 return 0;
04271 }
04272
04273 bio->iolen = l;
04274 bio->iocp = 0;
04275
04276 return 1;
04277 }
04278
04279
04280
04281
04282 static int inchar(struct baseio *bio, FILE *fi)
04283 {
04284 if (bio->iocp>=bio->iolen) {
04285 if (!inbuf(bio, fi))
04286 return EOF;
04287 }
04288
04289 return bio->iobuf[bio->iocp++];
04290 }
04291
04292
04293
04294
04295 static int ochar(struct baseio *bio, int c, FILE *so)
04296 {
04297 if (bio->linelength >= BASELINELEN) {
04298 if (fputs(ENDL, so) == EOF) {
04299 return -1;
04300 }
04301
04302 bio->linelength = 0;
04303 }
04304
04305 if (putc(((unsigned char) c), so) == EOF) {
04306 return -1;
04307 }
04308
04309 bio->linelength++;
04310
04311 return 1;
04312 }
04313
04314
04315
04316
04317
04318
04319
04320
04321
04322
04323 static int base_encode(char *filename, FILE *so)
04324 {
04325 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04326 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04327 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04328 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04329 int i, hiteof = 0;
04330 FILE *fi;
04331 struct baseio bio;
04332
04333 memset(&bio, 0, sizeof(bio));
04334 bio.iocp = BASEMAXINLINE;
04335
04336 if (!(fi = fopen(filename, "rb"))) {
04337 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04338 return -1;
04339 }
04340
04341 while (!hiteof){
04342 unsigned char igroup[3], ogroup[4];
04343 int c, n;
04344
04345 memset(igroup, 0, sizeof(igroup));
04346
04347 for (n = 0; n < 3; n++) {
04348 if ((c = inchar(&bio, fi)) == EOF) {
04349 hiteof = 1;
04350 break;
04351 }
04352
04353 igroup[n] = (unsigned char) c;
04354 }
04355
04356 if (n > 0) {
04357 ogroup[0]= dtable[igroup[0] >> 2];
04358 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04359 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04360 ogroup[3]= dtable[igroup[2] & 0x3F];
04361
04362 if (n < 3) {
04363 ogroup[3] = '=';
04364
04365 if (n < 2)
04366 ogroup[2] = '=';
04367 }
04368
04369 for (i = 0; i < 4; i++)
04370 ochar(&bio, ogroup[i], so);
04371 }
04372 }
04373
04374 fclose(fi);
04375
04376 if (fputs(ENDL, so) == EOF) {
04377 return 0;
04378 }
04379
04380 return 1;
04381 }
04382
04383 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)
04384 {
04385 char callerid[256];
04386 char num[12];
04387 char fromdir[256], fromfile[256];
04388 struct ast_config *msg_cfg;
04389 const char *origcallerid, *origtime;
04390 char origcidname[80], origcidnum[80], origdate[80];
04391 int inttime;
04392 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04393
04394
04395 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04396 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04397 snprintf(num, sizeof(num), "%d", msgnum);
04398 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04399 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04400 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04401 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04402 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04403 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04404 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04405 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04406 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04407 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04408
04409
04410 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04411 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04412 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04413 strcat(fromfile, ".txt");
04414 }
04415 if (!(msg_cfg = ast_config_load(fromfile, config_flags)) || !(valid_config(msg_cfg))) {
04416 if (option_debug > 0) {
04417 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04418 }
04419 return;
04420 }
04421
04422 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04423 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04424 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04425 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04426 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04427 }
04428
04429 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04430 struct timeval tv = { inttime, };
04431 struct ast_tm tm;
04432 ast_localtime(&tv, &tm, NULL);
04433 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04434 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04435 }
04436 ast_config_destroy(msg_cfg);
04437 }
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04448 {
04449 const char *ptr;
04450
04451
04452 ast_str_set(buf, maxlen, "\"");
04453 for (ptr = from; *ptr; ptr++) {
04454 if (*ptr == '"' || *ptr == '\\') {
04455 ast_str_append(buf, maxlen, "\\%c", *ptr);
04456 } else {
04457 ast_str_append(buf, maxlen, "%c", *ptr);
04458 }
04459 }
04460 ast_str_append(buf, maxlen, "\"");
04461
04462 return ast_str_buffer(*buf);
04463 }
04464
04465
04466
04467
04468
04469 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04470 {
04471 const struct vm_zone *z = NULL;
04472 struct timeval t = ast_tvnow();
04473
04474
04475 if (!ast_strlen_zero(vmu->zonetag)) {
04476
04477 AST_LIST_LOCK(&zones);
04478 AST_LIST_TRAVERSE(&zones, z, list) {
04479 if (!strcmp(z->name, vmu->zonetag))
04480 break;
04481 }
04482 AST_LIST_UNLOCK(&zones);
04483 }
04484 ast_localtime(&t, tm, z ? z->timezone : NULL);
04485 return tm;
04486 }
04487
04488
04489
04490
04491
04492 static int check_mime(const char *str)
04493 {
04494 for (; *str; str++) {
04495 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04496 return 1;
04497 }
04498 }
04499 return 0;
04500 }
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518
04519 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04520 {
04521 struct ast_str *tmp = ast_str_alloca(80);
04522 int first_section = 1;
04523
04524 ast_str_reset(*end);
04525 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04526 for (; *start; start++) {
04527 int need_encoding = 0;
04528 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04529 need_encoding = 1;
04530 }
04531 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04532 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04533 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04534 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04535
04536 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04537 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04538 first_section = 0;
04539 }
04540 if (need_encoding && *start == ' ') {
04541 ast_str_append(&tmp, -1, "_");
04542 } else if (need_encoding) {
04543 ast_str_append(&tmp, -1, "=%hhX", *start);
04544 } else {
04545 ast_str_append(&tmp, -1, "%c", *start);
04546 }
04547 }
04548 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04549 return ast_str_buffer(*end);
04550 }
04551
04552
04553
04554
04555
04556
04557
04558
04559
04560
04561
04562
04563
04564
04565
04566
04567
04568
04569
04570
04571
04572
04573
04574
04575 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)
04576 {
04577 char date[256];
04578 char host[MAXHOSTNAMELEN] = "";
04579 char who[256];
04580 char bound[256];
04581 char dur[256];
04582 struct ast_tm tm;
04583 char enc_cidnum[256] = "", enc_cidname[256] = "";
04584 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04585 char *greeting_attachment;
04586 char filename[256];
04587
04588 if (!str1 || !str2) {
04589 ast_free(str1);
04590 ast_free(str2);
04591 return;
04592 }
04593
04594 if (cidnum) {
04595 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04596 }
04597 if (cidname) {
04598 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04599 }
04600 gethostname(host, sizeof(host) - 1);
04601
04602 if (strchr(srcemail, '@')) {
04603 ast_copy_string(who, srcemail, sizeof(who));
04604 } else {
04605 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04606 }
04607
04608 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04609 if (greeting_attachment) {
04610 *greeting_attachment++ = '\0';
04611 }
04612
04613 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04614 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04615 fprintf(p, "Date: %s" ENDL, date);
04616
04617
04618 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04619
04620 if (!ast_strlen_zero(fromstring)) {
04621 struct ast_channel *ast;
04622 if ((ast = ast_dummy_channel_alloc())) {
04623 char *ptr;
04624 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04625 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04626
04627 if (check_mime(ast_str_buffer(str1))) {
04628 int first_line = 1;
04629 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04630 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04631 *ptr = '\0';
04632 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04633 first_line = 0;
04634
04635 ast_str_set(&str2, 0, "%s", ptr + 1);
04636 }
04637 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04638 } else {
04639 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04640 }
04641 ast = ast_channel_unref(ast);
04642 } else {
04643 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04644 }
04645 } else {
04646 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04647 }
04648
04649 if (check_mime(vmu->fullname)) {
04650 int first_line = 1;
04651 char *ptr;
04652 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04653 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04654 *ptr = '\0';
04655 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04656 first_line = 0;
04657
04658 ast_str_set(&str2, 0, "%s", ptr + 1);
04659 }
04660 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04661 } else {
04662 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04663 }
04664
04665 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04666 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04667 struct ast_channel *ast;
04668 if ((ast = ast_dummy_channel_alloc())) {
04669 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04670 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04671 if (check_mime(ast_str_buffer(str1))) {
04672 int first_line = 1;
04673 char *ptr;
04674 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04675 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04676 *ptr = '\0';
04677 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04678 first_line = 0;
04679
04680 ast_str_set(&str2, 0, "%s", ptr + 1);
04681 }
04682 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04683 } else {
04684 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04685 }
04686 ast = ast_channel_unref(ast);
04687 } else {
04688 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04689 }
04690 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04691 if (ast_strlen_zero(flag)) {
04692 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04693 } else {
04694 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04695 }
04696 } else {
04697 if (ast_strlen_zero(flag)) {
04698 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04699 } else {
04700 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04701 }
04702 }
04703
04704 fprintf(p, "Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
04705 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04706 if (imap) {
04707
04708 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04709
04710 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04711 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04712 #ifdef IMAP_STORAGE
04713 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04714 #else
04715 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04716 #endif
04717
04718 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04719 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04720 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04721 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04722 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04723 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04724 if (!ast_strlen_zero(category)) {
04725 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04726 } else {
04727 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04728 }
04729 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04730 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04731 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04732 }
04733 if (!ast_strlen_zero(cidnum)) {
04734 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04735 }
04736 if (!ast_strlen_zero(cidname)) {
04737 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04738 }
04739 fprintf(p, "MIME-Version: 1.0" ENDL);
04740 if (attach_user_voicemail) {
04741
04742 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%u", msgnum + 1, mailbox,
04743 (int) getpid(), (unsigned int) ast_random());
04744
04745 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04746 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04747 fprintf(p, "--%s" ENDL, bound);
04748 }
04749 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04750 if (emailbody || vmu->emailbody) {
04751 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04752 struct ast_channel *ast;
04753 if ((ast = ast_dummy_channel_alloc())) {
04754 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04755 ast_str_substitute_variables(&str1, 0, ast, e_body);
04756 #ifdef IMAP_STORAGE
04757 {
04758
04759 char *line = ast_str_buffer(str1), *next;
04760 do {
04761
04762 if ((next = strchr(line, '\n'))) {
04763 *next++ = '\0';
04764 }
04765 fprintf(p, "%s" ENDL, line);
04766 line = next;
04767 } while (!ast_strlen_zero(line));
04768 }
04769 #else
04770 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04771 #endif
04772 ast = ast_channel_unref(ast);
04773 } else {
04774 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04775 }
04776 } else if (msgnum > -1) {
04777 if (strcmp(vmu->mailbox, mailbox)) {
04778
04779 struct ast_config *msg_cfg;
04780 const char *v;
04781 int inttime;
04782 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04783 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04784
04785 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04786 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04787 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04788 strcat(fromfile, ".txt");
04789 }
04790 if ((msg_cfg = ast_config_load(fromfile, config_flags)) && valid_config(msg_cfg)) {
04791 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04792 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04793 }
04794
04795
04796
04797 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04798 struct timeval tv = { inttime, };
04799 struct ast_tm tm;
04800 ast_localtime(&tv, &tm, NULL);
04801 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04802 }
04803 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04804 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04805 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04806 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04807 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04808 date, origcallerid, origdate);
04809 ast_config_destroy(msg_cfg);
04810 } else {
04811 goto plain_message;
04812 }
04813 } else {
04814 plain_message:
04815 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04816 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04817 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04818 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04819 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04820 }
04821 } else {
04822 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04823 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04824 }
04825
04826 if (imap || attach_user_voicemail) {
04827 if (!ast_strlen_zero(attach2)) {
04828 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04829 ast_debug(5, "creating second attachment filename %s\n", filename);
04830 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04831 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04832 ast_debug(5, "creating attachment filename %s\n", filename);
04833 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04834 } else {
04835 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04836 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04837 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04838 }
04839 }
04840 ast_free(str1);
04841 ast_free(str2);
04842 }
04843
04844 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)
04845 {
04846 char tmpdir[256], newtmp[256];
04847 char fname[256];
04848 char tmpcmd[256];
04849 int tmpfd = -1;
04850 int soxstatus = 0;
04851
04852
04853 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04854
04855 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04856 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04857 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04858 tmpfd = mkstemp(newtmp);
04859 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04860 ast_debug(3, "newtmp: %s\n", newtmp);
04861 if (tmpfd > -1) {
04862 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04863 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04864 attach = newtmp;
04865 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04866 } else {
04867 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04868 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04869 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04870 }
04871 }
04872 }
04873 fprintf(p, "--%s" ENDL, bound);
04874 if (msgnum > -1)
04875 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04876 else
04877 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04878 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04879 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04880 if (msgnum > -1)
04881 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04882 else
04883 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04884 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04885 base_encode(fname, p);
04886 if (last)
04887 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04888 if (tmpfd > -1) {
04889 if (soxstatus == 0) {
04890 unlink(fname);
04891 }
04892 close(tmpfd);
04893 unlink(newtmp);
04894 }
04895 return 0;
04896 }
04897
04898 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)
04899 {
04900 FILE *p = NULL;
04901 char tmp[80] = "/tmp/astmail-XXXXXX";
04902 char tmp2[256];
04903 char *stringp;
04904
04905 if (vmu && ast_strlen_zero(vmu->email)) {
04906 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04907 return(0);
04908 }
04909
04910
04911 format = ast_strdupa(format);
04912 stringp = format;
04913 strsep(&stringp, "|");
04914
04915 if (!strcmp(format, "wav49"))
04916 format = "WAV";
04917 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %u\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04918
04919
04920 if ((p = vm_mkftemp(tmp)) == NULL) {
04921 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04922 return -1;
04923 } else {
04924 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04925 fclose(p);
04926 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04927 ast_safe_system(tmp2);
04928 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04929 }
04930 return 0;
04931 }
04932
04933 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)
04934 {
04935 char enc_cidnum[256], enc_cidname[256];
04936 char date[256];
04937 char host[MAXHOSTNAMELEN] = "";
04938 char who[256];
04939 char dur[PATH_MAX];
04940 char tmp[80] = "/tmp/astmail-XXXXXX";
04941 char tmp2[PATH_MAX];
04942 struct ast_tm tm;
04943 FILE *p;
04944 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04945
04946 if (!str1 || !str2) {
04947 ast_free(str1);
04948 ast_free(str2);
04949 return -1;
04950 }
04951
04952 if (cidnum) {
04953 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04954 }
04955 if (cidname) {
04956 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04957 }
04958
04959 if ((p = vm_mkftemp(tmp)) == NULL) {
04960 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04961 ast_free(str1);
04962 ast_free(str2);
04963 return -1;
04964 }
04965 gethostname(host, sizeof(host)-1);
04966 if (strchr(srcemail, '@')) {
04967 ast_copy_string(who, srcemail, sizeof(who));
04968 } else {
04969 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04970 }
04971 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04972 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04973 fprintf(p, "Date: %s\n", date);
04974
04975
04976 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04977
04978 if (!ast_strlen_zero(pagerfromstring)) {
04979 struct ast_channel *ast;
04980 if ((ast = ast_dummy_channel_alloc())) {
04981 char *ptr;
04982 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04983 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04984
04985 if (check_mime(ast_str_buffer(str1))) {
04986 int first_line = 1;
04987 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04988 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04989 *ptr = '\0';
04990 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04991 first_line = 0;
04992
04993 ast_str_set(&str2, 0, "%s", ptr + 1);
04994 }
04995 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04996 } else {
04997 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04998 }
04999 ast = ast_channel_unref(ast);
05000 } else {
05001 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05002 }
05003 } else {
05004 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
05005 }
05006
05007 if (check_mime(vmu->fullname)) {
05008 int first_line = 1;
05009 char *ptr;
05010 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
05011 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05012 *ptr = '\0';
05013 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
05014 first_line = 0;
05015
05016 ast_str_set(&str2, 0, "%s", ptr + 1);
05017 }
05018 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
05019 } else {
05020 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
05021 }
05022
05023 if (!ast_strlen_zero(pagersubject)) {
05024 struct ast_channel *ast;
05025 if ((ast = ast_dummy_channel_alloc())) {
05026 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05027 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
05028 if (check_mime(ast_str_buffer(str1))) {
05029 int first_line = 1;
05030 char *ptr;
05031 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
05032 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05033 *ptr = '\0';
05034 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05035 first_line = 0;
05036
05037 ast_str_set(&str2, 0, "%s", ptr + 1);
05038 }
05039 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05040 } else {
05041 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
05042 }
05043 ast = ast_channel_unref(ast);
05044 } else {
05045 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05046 }
05047 } else {
05048 if (ast_strlen_zero(flag)) {
05049 fprintf(p, "Subject: New VM\n\n");
05050 } else {
05051 fprintf(p, "Subject: New %s VM\n\n", flag);
05052 }
05053 }
05054
05055 if (pagerbody) {
05056 struct ast_channel *ast;
05057 if ((ast = ast_dummy_channel_alloc())) {
05058 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05059 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05060 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05061 ast = ast_channel_unref(ast);
05062 } else {
05063 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05064 }
05065 } else {
05066 fprintf(p, "New %s long %s msg in box %s\n"
05067 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05068 }
05069
05070 fclose(p);
05071 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05072 ast_safe_system(tmp2);
05073 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05074 ast_free(str1);
05075 ast_free(str2);
05076 return 0;
05077 }
05078
05079
05080
05081
05082
05083
05084
05085
05086
05087
05088 static int get_date(char *s, int len)
05089 {
05090 struct ast_tm tm;
05091 struct timeval t = ast_tvnow();
05092
05093 ast_localtime(&t, &tm, "UTC");
05094
05095 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05096 }
05097
05098 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05099 {
05100 int res;
05101 char fn[PATH_MAX];
05102 char dest[PATH_MAX];
05103
05104 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05105
05106 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05107 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05108 return -1;
05109 }
05110
05111 RETRIEVE(fn, -1, ext, context);
05112 if (ast_fileexists(fn, NULL, NULL) > 0) {
05113 res = ast_stream_and_wait(chan, fn, ecodes);
05114 if (res) {
05115 DISPOSE(fn, -1);
05116 return res;
05117 }
05118 } else {
05119
05120 DISPOSE(fn, -1);
05121 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05122 if (res)
05123 return res;
05124 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05125 if (res)
05126 return res;
05127 }
05128 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05129 return res;
05130 }
05131
05132 static void free_zone(struct vm_zone *z)
05133 {
05134 ast_free(z);
05135 }
05136
05137 #ifdef ODBC_STORAGE
05138 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05139 {
05140 int x = -1;
05141 int res;
05142 SQLHSTMT stmt = NULL;
05143 char sql[PATH_MAX];
05144 char rowdata[20];
05145 char tmp[PATH_MAX] = "";
05146 struct odbc_obj *obj = NULL;
05147 char *context;
05148 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05149
05150 if (newmsgs)
05151 *newmsgs = 0;
05152 if (oldmsgs)
05153 *oldmsgs = 0;
05154 if (urgentmsgs)
05155 *urgentmsgs = 0;
05156
05157
05158 if (ast_strlen_zero(mailbox))
05159 return 0;
05160
05161 ast_copy_string(tmp, mailbox, sizeof(tmp));
05162
05163 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05164 int u, n, o;
05165 char *next, *remaining = tmp;
05166 while ((next = strsep(&remaining, " ,"))) {
05167 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05168 return -1;
05169 }
05170 if (urgentmsgs) {
05171 *urgentmsgs += u;
05172 }
05173 if (newmsgs) {
05174 *newmsgs += n;
05175 }
05176 if (oldmsgs) {
05177 *oldmsgs += o;
05178 }
05179 }
05180 return 0;
05181 }
05182
05183 context = strchr(tmp, '@');
05184 if (context) {
05185 *context = '\0';
05186 context++;
05187 } else
05188 context = "default";
05189
05190 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05191 do {
05192 if (newmsgs) {
05193 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05194 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05195 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05196 break;
05197 }
05198 res = SQLFetch(stmt);
05199 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05200 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05201 break;
05202 }
05203 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05204 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05205 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05206 break;
05207 }
05208 *newmsgs = atoi(rowdata);
05209 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05210 }
05211
05212 if (oldmsgs) {
05213 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05214 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05215 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05216 break;
05217 }
05218 res = SQLFetch(stmt);
05219 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05220 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05221 break;
05222 }
05223 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05224 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05225 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05226 break;
05227 }
05228 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05229 *oldmsgs = atoi(rowdata);
05230 }
05231
05232 if (urgentmsgs) {
05233 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05234 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05235 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05236 break;
05237 }
05238 res = SQLFetch(stmt);
05239 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05240 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05241 break;
05242 }
05243 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05244 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05245 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05246 break;
05247 }
05248 *urgentmsgs = atoi(rowdata);
05249 }
05250
05251 x = 0;
05252 } while (0);
05253 } else {
05254 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05255 }
05256
05257 if (stmt) {
05258 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05259 }
05260 if (obj) {
05261 ast_odbc_release_obj(obj);
05262 }
05263 return x;
05264 }
05265
05266
05267
05268
05269
05270
05271
05272
05273
05274
05275 static int messagecount(const char *context, const char *mailbox, const char *folder)
05276 {
05277 struct odbc_obj *obj = NULL;
05278 int nummsgs = 0;
05279 int res;
05280 SQLHSTMT stmt = NULL;
05281 char sql[PATH_MAX];
05282 char rowdata[20];
05283 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05284 if (!folder)
05285 folder = "INBOX";
05286
05287 if (ast_strlen_zero(mailbox))
05288 return 0;
05289
05290 obj = ast_odbc_request_obj(odbc_database, 0);
05291 if (obj) {
05292 if (!strcmp(folder, "INBOX")) {
05293 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);
05294 } else {
05295 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05296 }
05297 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05298 if (!stmt) {
05299 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05300 goto yuck;
05301 }
05302 res = SQLFetch(stmt);
05303 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05304 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05305 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05306 goto yuck;
05307 }
05308 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05309 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05310 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05311 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05312 goto yuck;
05313 }
05314 nummsgs = atoi(rowdata);
05315 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05316 } else
05317 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05318
05319 yuck:
05320 if (obj)
05321 ast_odbc_release_obj(obj);
05322 return nummsgs;
05323 }
05324
05325
05326
05327
05328
05329
05330
05331
05332
05333 static int has_voicemail(const char *mailbox, const char *folder)
05334 {
05335 char tmp[256], *tmp2 = tmp, *box, *context;
05336 ast_copy_string(tmp, mailbox, sizeof(tmp));
05337 while ((context = box = strsep(&tmp2, ",&"))) {
05338 strsep(&context, "@");
05339 if (ast_strlen_zero(context))
05340 context = "default";
05341 if (messagecount(context, box, folder))
05342 return 1;
05343 }
05344 return 0;
05345 }
05346 #endif
05347 #ifndef IMAP_STORAGE
05348
05349
05350
05351
05352
05353
05354
05355
05356
05357
05358
05359
05360
05361
05362
05363
05364 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)
05365 {
05366 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05367 const char *frombox = mbox(vmu, imbox);
05368 const char *userfolder;
05369 int recipmsgnum;
05370 int res = 0;
05371
05372 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05373
05374 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05375 userfolder = "Urgent";
05376 } else {
05377 userfolder = "INBOX";
05378 }
05379
05380 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05381
05382 if (!dir)
05383 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05384 else
05385 ast_copy_string(fromdir, dir, sizeof(fromdir));
05386
05387 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05388 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05389
05390 if (vm_lock_path(todir))
05391 return ERROR_LOCK_PATH;
05392
05393 recipmsgnum = last_message_index(recip, todir) + 1;
05394 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05395 make_file(topath, sizeof(topath), todir, recipmsgnum);
05396 #ifndef ODBC_STORAGE
05397 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05398 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05399 } else {
05400 #endif
05401
05402
05403
05404 copy_plain_file(frompath, topath);
05405 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05406 vm_delete(topath);
05407 #ifndef ODBC_STORAGE
05408 }
05409 #endif
05410 } else {
05411 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05412 res = -1;
05413 }
05414 ast_unlock_path(todir);
05415 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05416 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05417 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05418 flag);
05419
05420 return res;
05421 }
05422 #endif
05423 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05424
05425 static int messagecount(const char *context, const char *mailbox, const char *folder)
05426 {
05427 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05428 }
05429
05430 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05431 {
05432 DIR *dir;
05433 struct dirent *de;
05434 char fn[256];
05435 int ret = 0;
05436
05437
05438 if (ast_strlen_zero(mailbox))
05439 return 0;
05440
05441 if (ast_strlen_zero(folder))
05442 folder = "INBOX";
05443 if (ast_strlen_zero(context))
05444 context = "default";
05445
05446 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05447
05448 if (!(dir = opendir(fn)))
05449 return 0;
05450
05451 while ((de = readdir(dir))) {
05452 if (!strncasecmp(de->d_name, "msg", 3)) {
05453 if (shortcircuit) {
05454 ret = 1;
05455 break;
05456 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05457 ret++;
05458 }
05459 }
05460 }
05461
05462 closedir(dir);
05463
05464 return ret;
05465 }
05466
05467
05468
05469
05470
05471
05472
05473
05474
05475
05476 static int has_voicemail(const char *mailbox, const char *folder)
05477 {
05478 char tmp[256], *tmp2 = tmp, *box, *context;
05479 ast_copy_string(tmp, mailbox, sizeof(tmp));
05480 if (ast_strlen_zero(folder)) {
05481 folder = "INBOX";
05482 }
05483 while ((box = strsep(&tmp2, ",&"))) {
05484 if ((context = strchr(box, '@')))
05485 *context++ = '\0';
05486 else
05487 context = "default";
05488 if (__has_voicemail(context, box, folder, 1))
05489 return 1;
05490
05491 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05492 return 1;
05493 }
05494 }
05495 return 0;
05496 }
05497
05498
05499 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05500 {
05501 char tmp[256];
05502 char *context;
05503
05504
05505 if (ast_strlen_zero(mailbox))
05506 return 0;
05507
05508 if (newmsgs)
05509 *newmsgs = 0;
05510 if (oldmsgs)
05511 *oldmsgs = 0;
05512 if (urgentmsgs)
05513 *urgentmsgs = 0;
05514
05515 if (strchr(mailbox, ',')) {
05516 int tmpnew, tmpold, tmpurgent;
05517 char *mb, *cur;
05518
05519 ast_copy_string(tmp, mailbox, sizeof(tmp));
05520 mb = tmp;
05521 while ((cur = strsep(&mb, ", "))) {
05522 if (!ast_strlen_zero(cur)) {
05523 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05524 return -1;
05525 else {
05526 if (newmsgs)
05527 *newmsgs += tmpnew;
05528 if (oldmsgs)
05529 *oldmsgs += tmpold;
05530 if (urgentmsgs)
05531 *urgentmsgs += tmpurgent;
05532 }
05533 }
05534 }
05535 return 0;
05536 }
05537
05538 ast_copy_string(tmp, mailbox, sizeof(tmp));
05539
05540 if ((context = strchr(tmp, '@')))
05541 *context++ = '\0';
05542 else
05543 context = "default";
05544
05545 if (newmsgs)
05546 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05547 if (oldmsgs)
05548 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05549 if (urgentmsgs)
05550 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05551
05552 return 0;
05553 }
05554
05555 #endif
05556
05557
05558 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05559 {
05560 int urgentmsgs = 0;
05561 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05562 if (newmsgs) {
05563 *newmsgs += urgentmsgs;
05564 }
05565 return res;
05566 }
05567
05568 static void run_externnotify(char *context, char *extension, const char *flag)
05569 {
05570 char arguments[255];
05571 char ext_context[256] = "";
05572 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05573 struct ast_smdi_mwi_message *mwi_msg;
05574
05575 if (!ast_strlen_zero(context))
05576 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05577 else
05578 ast_copy_string(ext_context, extension, sizeof(ext_context));
05579
05580 if (smdi_iface) {
05581 if (ast_app_has_voicemail(ext_context, NULL))
05582 ast_smdi_mwi_set(smdi_iface, extension);
05583 else
05584 ast_smdi_mwi_unset(smdi_iface, extension);
05585
05586 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05587 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05588 if (!strncmp(mwi_msg->cause, "INV", 3))
05589 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05590 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05591 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05592 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05593 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05594 } else {
05595 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05596 }
05597 }
05598
05599 if (!ast_strlen_zero(externnotify)) {
05600 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05601 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05602 } else {
05603 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &",
05604 externnotify, S_OR(context, "\"\""),
05605 extension, newvoicemails,
05606 oldvoicemails, urgentvoicemails);
05607 ast_debug(1, "Executing %s\n", arguments);
05608 ast_safe_system(arguments);
05609 }
05610 }
05611 }
05612
05613
05614
05615
05616
05617
05618 struct leave_vm_options {
05619 unsigned int flags;
05620 signed char record_gain;
05621 char *exitcontext;
05622 };
05623
05624
05625
05626
05627
05628
05629
05630
05631
05632
05633
05634 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05635 {
05636 #ifdef IMAP_STORAGE
05637 int newmsgs, oldmsgs;
05638 #else
05639 char urgdir[PATH_MAX];
05640 #endif
05641 char txtfile[PATH_MAX];
05642 char tmptxtfile[PATH_MAX];
05643 struct vm_state *vms = NULL;
05644 char callerid[256];
05645 FILE *txt;
05646 char date[256];
05647 int txtdes;
05648 int res = 0;
05649 int msgnum;
05650 int duration = 0;
05651 int sound_duration = 0;
05652 int ausemacro = 0;
05653 int ousemacro = 0;
05654 int ouseexten = 0;
05655 char tmpdur[16];
05656 char priority[16];
05657 char origtime[16];
05658 char dir[PATH_MAX];
05659 char tmpdir[PATH_MAX];
05660 char fn[PATH_MAX];
05661 char prefile[PATH_MAX] = "";
05662 char tempfile[PATH_MAX] = "";
05663 char ext_context[256] = "";
05664 char fmt[80];
05665 char *context;
05666 char ecodes[17] = "#";
05667 struct ast_str *tmp = ast_str_create(16);
05668 char *tmpptr;
05669 struct ast_vm_user *vmu;
05670 struct ast_vm_user svm;
05671 const char *category = NULL;
05672 const char *code;
05673 const char *alldtmf = "0123456789ABCD*#";
05674 char flag[80];
05675
05676 if (!tmp) {
05677 return -1;
05678 }
05679
05680 ast_str_set(&tmp, 0, "%s", ext);
05681 ext = ast_str_buffer(tmp);
05682 if ((context = strchr(ext, '@'))) {
05683 *context++ = '\0';
05684 tmpptr = strchr(context, '&');
05685 } else {
05686 tmpptr = strchr(ext, '&');
05687 }
05688
05689 if (tmpptr)
05690 *tmpptr++ = '\0';
05691
05692 ast_channel_lock(chan);
05693 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05694 category = ast_strdupa(category);
05695 }
05696 ast_channel_unlock(chan);
05697
05698 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05699 ast_copy_string(flag, "Urgent", sizeof(flag));
05700 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05701 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05702 } else {
05703 flag[0] = '\0';
05704 }
05705
05706 ast_debug(3, "Before find_user\n");
05707 if (!(vmu = find_user(&svm, context, ext))) {
05708 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05709 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05710 ast_free(tmp);
05711 return res;
05712 }
05713
05714 if (strcmp(vmu->context, "default"))
05715 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05716 else
05717 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05718
05719
05720
05721
05722
05723
05724 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05725 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05726 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05727 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05728 }
05729
05730
05731
05732
05733 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05734 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05735 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05736 ast_free(tmp);
05737 return -1;
05738 }
05739 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05740 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05741 ast_copy_string(prefile, tempfile, sizeof(prefile));
05742
05743 DISPOSE(tempfile, -1);
05744
05745 #ifndef IMAP_STORAGE
05746 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05747 #else
05748 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05749 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05750 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05751 }
05752 #endif
05753
05754
05755 if (ast_test_flag(vmu, VM_OPERATOR)) {
05756 if (!ast_strlen_zero(vmu->exit)) {
05757 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05758 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05759 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05760 ouseexten = 1;
05761 }
05762 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05763 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05764 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05765 ouseexten = 1;
05766 } else if (!ast_strlen_zero(chan->macrocontext)
05767 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05768 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05769 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05770 ousemacro = 1;
05771 }
05772 }
05773
05774 if (!ast_strlen_zero(vmu->exit)) {
05775 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05776 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05777 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05778 }
05779 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05780 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05781 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05782 } else if (!ast_strlen_zero(chan->macrocontext)
05783 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05784 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05785 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05786 ausemacro = 1;
05787 }
05788
05789 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05790 for (code = alldtmf; *code; code++) {
05791 char e[2] = "";
05792 e[0] = *code;
05793 if (strchr(ecodes, e[0]) == NULL
05794 && ast_canmatch_extension(chan,
05795 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05796 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05797 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05798 }
05799 }
05800 }
05801
05802
05803 if (!ast_strlen_zero(prefile)) {
05804 #ifdef ODBC_STORAGE
05805 int success =
05806 #endif
05807 RETRIEVE(prefile, -1, ext, context);
05808 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05809 if (ast_streamfile(chan, prefile, chan->language) > -1)
05810 res = ast_waitstream(chan, ecodes);
05811 #ifdef ODBC_STORAGE
05812 if (success == -1) {
05813
05814 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05815 store_file(prefile, vmu->mailbox, vmu->context, -1);
05816 }
05817 #endif
05818 } else {
05819 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05820 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05821 }
05822 DISPOSE(prefile, -1);
05823 if (res < 0) {
05824 ast_debug(1, "Hang up during prefile playback\n");
05825 free_user(vmu);
05826 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05827 ast_free(tmp);
05828 return -1;
05829 }
05830 }
05831 if (res == '#') {
05832
05833 ast_set_flag(options, OPT_SILENT);
05834 res = 0;
05835 }
05836
05837 if (vmu->maxmsg == 0) {
05838 if (option_debug > 2)
05839 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05840 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05841 goto leave_vm_out;
05842 }
05843 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05844 res = ast_stream_and_wait(chan, INTRO, ecodes);
05845 if (res == '#') {
05846 ast_set_flag(options, OPT_SILENT);
05847 res = 0;
05848 }
05849 }
05850 if (res > 0)
05851 ast_stopstream(chan);
05852
05853
05854 if (res == '*') {
05855 chan->exten[0] = 'a';
05856 chan->exten[1] = '\0';
05857 if (!ast_strlen_zero(vmu->exit)) {
05858 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05859 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05860 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05861 }
05862 chan->priority = 0;
05863 free_user(vmu);
05864 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05865 ast_free(tmp);
05866 return 0;
05867 }
05868
05869
05870 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05871 transfer:
05872 if (ouseexten || ousemacro) {
05873 chan->exten[0] = 'o';
05874 chan->exten[1] = '\0';
05875 if (!ast_strlen_zero(vmu->exit)) {
05876 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05877 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05878 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05879 }
05880 ast_play_and_wait(chan, "transfer");
05881 chan->priority = 0;
05882 free_user(vmu);
05883 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05884 }
05885 ast_free(tmp);
05886 return OPERATOR_EXIT;
05887 }
05888
05889
05890 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05891 if (!ast_strlen_zero(options->exitcontext)) {
05892 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05893 }
05894 free_user(vmu);
05895 ast_free(tmp);
05896 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05897 return res;
05898 }
05899
05900 if (res < 0) {
05901 free_user(vmu);
05902 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05903 ast_free(tmp);
05904 return -1;
05905 }
05906
05907 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05908 if (!ast_strlen_zero(fmt)) {
05909 msgnum = 0;
05910
05911 #ifdef IMAP_STORAGE
05912
05913
05914 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05915 if (res < 0) {
05916 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05917 ast_free(tmp);
05918 return -1;
05919 }
05920 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05921
05922
05923
05924
05925 if (!(vms = create_vm_state_from_user(vmu))) {
05926 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05927 ast_free(tmp);
05928 return -1;
05929 }
05930 }
05931 vms->newmessages++;
05932
05933
05934 msgnum = newmsgs + oldmsgs;
05935 ast_debug(3, "Messagecount set to %d\n", msgnum);
05936 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05937
05938 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05939
05940 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05941 goto leave_vm_out;
05942 }
05943 #else
05944 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05945 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05946 if (!res)
05947 res = ast_waitstream(chan, "");
05948 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05949 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05950 inprocess_count(vmu->mailbox, vmu->context, -1);
05951 goto leave_vm_out;
05952 }
05953
05954 #endif
05955 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05956 txtdes = mkstemp(tmptxtfile);
05957 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05958 if (txtdes < 0) {
05959 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05960 if (!res)
05961 res = ast_waitstream(chan, "");
05962 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05963 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05964 inprocess_count(vmu->mailbox, vmu->context, -1);
05965 goto leave_vm_out;
05966 }
05967
05968
05969 if (res >= 0) {
05970
05971 res = ast_stream_and_wait(chan, "beep", "");
05972 }
05973
05974
05975 if (ast_check_realtime("voicemail_data")) {
05976 snprintf(priority, sizeof(priority), "%d", chan->priority);
05977 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05978 get_date(date, sizeof(date));
05979 ast_callerid_merge(callerid, sizeof(callerid),
05980 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05981 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05982 "Unknown");
05983 ast_store_realtime("voicemail_data",
05984 "origmailbox", ext,
05985 "context", chan->context,
05986 "macrocontext", chan->macrocontext,
05987 "exten", chan->exten,
05988 "priority", priority,
05989 "callerchan", chan->name,
05990 "callerid", callerid,
05991 "origdate", date,
05992 "origtime", origtime,
05993 "category", S_OR(category, ""),
05994 "filename", tmptxtfile,
05995 SENTINEL);
05996 }
05997
05998
05999 txt = fdopen(txtdes, "w+");
06000 if (txt) {
06001 get_date(date, sizeof(date));
06002 ast_callerid_merge(callerid, sizeof(callerid),
06003 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06004 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06005 "Unknown");
06006 fprintf(txt,
06007 ";\n"
06008 "; Message Information file\n"
06009 ";\n"
06010 "[message]\n"
06011 "origmailbox=%s\n"
06012 "context=%s\n"
06013 "macrocontext=%s\n"
06014 "exten=%s\n"
06015 "rdnis=%s\n"
06016 "priority=%d\n"
06017 "callerchan=%s\n"
06018 "callerid=%s\n"
06019 "origdate=%s\n"
06020 "origtime=%ld\n"
06021 "category=%s\n",
06022 ext,
06023 chan->context,
06024 chan->macrocontext,
06025 chan->exten,
06026 S_COR(chan->redirecting.from.number.valid,
06027 chan->redirecting.from.number.str, "unknown"),
06028 chan->priority,
06029 chan->name,
06030 callerid,
06031 date, (long) time(NULL),
06032 category ? category : "");
06033 } else {
06034 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
06035 inprocess_count(vmu->mailbox, vmu->context, -1);
06036 if (ast_check_realtime("voicemail_data")) {
06037 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06038 }
06039 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
06040 goto leave_vm_out;
06041 }
06042 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
06043
06044 if (txt) {
06045 fprintf(txt, "flag=%s\n", flag);
06046 if (sound_duration < vmu->minsecs) {
06047 fclose(txt);
06048 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06049 ast_filedelete(tmptxtfile, NULL);
06050 unlink(tmptxtfile);
06051 if (ast_check_realtime("voicemail_data")) {
06052 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06053 }
06054 inprocess_count(vmu->mailbox, vmu->context, -1);
06055 } else {
06056 fprintf(txt, "duration=%d\n", duration);
06057 fclose(txt);
06058 if (vm_lock_path(dir)) {
06059 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06060
06061 ast_filedelete(tmptxtfile, NULL);
06062 unlink(tmptxtfile);
06063 inprocess_count(vmu->mailbox, vmu->context, -1);
06064 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06065 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06066 unlink(tmptxtfile);
06067 ast_unlock_path(dir);
06068 inprocess_count(vmu->mailbox, vmu->context, -1);
06069 if (ast_check_realtime("voicemail_data")) {
06070 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06071 }
06072 } else {
06073 #ifndef IMAP_STORAGE
06074 msgnum = last_message_index(vmu, dir) + 1;
06075 #endif
06076 make_file(fn, sizeof(fn), dir, msgnum);
06077
06078
06079 #ifndef IMAP_STORAGE
06080 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06081 #else
06082 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06083 #endif
06084
06085 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06086 ast_filerename(tmptxtfile, fn, NULL);
06087 rename(tmptxtfile, txtfile);
06088 inprocess_count(vmu->mailbox, vmu->context, -1);
06089
06090
06091
06092 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06093 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06094
06095 ast_unlock_path(dir);
06096 if (ast_check_realtime("voicemail_data")) {
06097 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06098 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06099 }
06100
06101
06102
06103 if (ast_fileexists(fn, NULL, NULL) > 0) {
06104 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06105 }
06106
06107
06108 while (tmpptr) {
06109 struct ast_vm_user recipu, *recip;
06110 char *exten, *cntx;
06111
06112 exten = strsep(&tmpptr, "&");
06113 cntx = strchr(exten, '@');
06114 if (cntx) {
06115 *cntx = '\0';
06116 cntx++;
06117 }
06118 if ((recip = find_user(&recipu, cntx, exten))) {
06119 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06120 free_user(recip);
06121 }
06122 }
06123 #ifndef IMAP_STORAGE
06124 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06125
06126 char sfn[PATH_MAX];
06127 char dfn[PATH_MAX];
06128 int x;
06129
06130 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06131 x = last_message_index(vmu, urgdir) + 1;
06132 make_file(sfn, sizeof(sfn), dir, msgnum);
06133 make_file(dfn, sizeof(dfn), urgdir, x);
06134 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06135 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06136
06137 ast_copy_string(fn, dfn, sizeof(fn));
06138 msgnum = x;
06139 }
06140 #endif
06141
06142 if (ast_fileexists(fn, NULL, NULL)) {
06143 #ifdef IMAP_STORAGE
06144 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06145 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06146 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06147 flag);
06148 #else
06149 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06150 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06151 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06152 flag);
06153 #endif
06154 }
06155
06156
06157 if (ast_fileexists(fn, NULL, NULL)) {
06158 DISPOSE(dir, msgnum);
06159 }
06160 }
06161 }
06162 } else {
06163 inprocess_count(vmu->mailbox, vmu->context, -1);
06164 }
06165 if (res == '0') {
06166 goto transfer;
06167 } else if (res > 0 && res != 't')
06168 res = 0;
06169
06170 if (sound_duration < vmu->minsecs)
06171
06172 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06173 else
06174 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06175 } else
06176 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06177 leave_vm_out:
06178 free_user(vmu);
06179
06180 #ifdef IMAP_STORAGE
06181
06182 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06183 if (expungeonhangup == 1) {
06184 ast_mutex_lock(&vms->lock);
06185 #ifdef HAVE_IMAP_TK2006
06186 if (LEVELUIDPLUS (vms->mailstream)) {
06187 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06188 } else
06189 #endif
06190 mail_expunge(vms->mailstream);
06191 ast_mutex_unlock(&vms->lock);
06192 }
06193 #endif
06194
06195 ast_free(tmp);
06196 return res;
06197 }
06198
06199 #if !defined(IMAP_STORAGE)
06200 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06201 {
06202
06203
06204 int x, dest;
06205 char sfn[PATH_MAX];
06206 char dfn[PATH_MAX];
06207
06208 if (vm_lock_path(dir)) {
06209 return ERROR_LOCK_PATH;
06210 }
06211
06212 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06213 make_file(sfn, sizeof(sfn), dir, x);
06214 if (EXISTS(dir, x, sfn, NULL)) {
06215
06216 if (x != dest) {
06217 make_file(dfn, sizeof(dfn), dir, dest);
06218 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06219 }
06220
06221 dest++;
06222 }
06223 }
06224 ast_unlock_path(dir);
06225
06226 return dest;
06227 }
06228 #endif
06229
06230 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06231 {
06232 int d;
06233 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06234 return d;
06235 }
06236
06237 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06238 {
06239 #ifdef IMAP_STORAGE
06240
06241
06242 char sequence[10];
06243 char mailbox[256];
06244 int res;
06245
06246
06247 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06248
06249 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06250 ast_mutex_lock(&vms->lock);
06251
06252 if (box == OLD_FOLDER) {
06253 mail_setflag(vms->mailstream, sequence, "\\Seen");
06254 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06255 } else if (box == NEW_FOLDER) {
06256 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06257 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06258 }
06259 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06260 ast_mutex_unlock(&vms->lock);
06261 return 0;
06262 }
06263
06264 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06265 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06266 if (mail_create(vms->mailstream, mailbox) == NIL)
06267 ast_debug(5, "Folder exists.\n");
06268 else
06269 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06270 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06271 ast_mutex_unlock(&vms->lock);
06272 return res;
06273 #else
06274 char *dir = vms->curdir;
06275 char *username = vms->username;
06276 char *context = vmu->context;
06277 char sfn[PATH_MAX];
06278 char dfn[PATH_MAX];
06279 char ddir[PATH_MAX];
06280 const char *dbox = mbox(vmu, box);
06281 int x, i;
06282 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06283
06284 if (vm_lock_path(ddir))
06285 return ERROR_LOCK_PATH;
06286
06287 x = last_message_index(vmu, ddir) + 1;
06288
06289 if (box == 10 && x >= vmu->maxdeletedmsg) {
06290 x--;
06291 for (i = 1; i <= x; i++) {
06292
06293 make_file(sfn, sizeof(sfn), ddir, i);
06294 make_file(dfn, sizeof(dfn), ddir, i - 1);
06295 if (EXISTS(ddir, i, sfn, NULL)) {
06296 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06297 } else
06298 break;
06299 }
06300 } else {
06301 if (x >= vmu->maxmsg) {
06302 ast_unlock_path(ddir);
06303 return -1;
06304 }
06305 }
06306 make_file(sfn, sizeof(sfn), dir, msg);
06307 make_file(dfn, sizeof(dfn), ddir, x);
06308 if (strcmp(sfn, dfn)) {
06309 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06310 }
06311 ast_unlock_path(ddir);
06312 #endif
06313 return 0;
06314 }
06315
06316 static int adsi_logo(unsigned char *buf)
06317 {
06318 int bytes = 0;
06319 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06320 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06321 return bytes;
06322 }
06323
06324 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06325 {
06326 unsigned char buf[256];
06327 int bytes = 0;
06328 int x;
06329 char num[5];
06330
06331 *useadsi = 0;
06332 bytes += ast_adsi_data_mode(buf + bytes);
06333 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06334
06335 bytes = 0;
06336 bytes += adsi_logo(buf);
06337 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06338 #ifdef DISPLAY
06339 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06340 #endif
06341 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06342 bytes += ast_adsi_data_mode(buf + bytes);
06343 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06344
06345 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06346 bytes = 0;
06347 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06348 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06349 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06350 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06351 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06352 return 0;
06353 }
06354
06355 #ifdef DISPLAY
06356
06357 bytes = 0;
06358 bytes += ast_adsi_logo(buf);
06359 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06360 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06361 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06362 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06363 #endif
06364 bytes = 0;
06365 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06366 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06367 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06368 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06369 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06370 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06371 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06372
06373 #ifdef DISPLAY
06374
06375 bytes = 0;
06376 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06377 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06378
06379 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06380 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06381 #endif
06382
06383 bytes = 0;
06384
06385 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06386 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06387 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06388 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06389 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06390 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06391 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06392
06393 #ifdef DISPLAY
06394
06395 bytes = 0;
06396 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06397 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06398 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06399 #endif
06400
06401 bytes = 0;
06402 for (x = 0; x < 5; x++) {
06403 snprintf(num, sizeof(num), "%d", x);
06404 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06405 }
06406 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06407 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06408
06409 #ifdef DISPLAY
06410
06411 bytes = 0;
06412 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06413 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06414 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06415 #endif
06416
06417 if (ast_adsi_end_download(chan)) {
06418 bytes = 0;
06419 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06420 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06421 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06422 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06423 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06424 return 0;
06425 }
06426 bytes = 0;
06427 bytes += ast_adsi_download_disconnect(buf + bytes);
06428 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06429 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06430
06431 ast_debug(1, "Done downloading scripts...\n");
06432
06433 #ifdef DISPLAY
06434
06435 bytes = 0;
06436 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06437 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06438 #endif
06439 ast_debug(1, "Restarting session...\n");
06440
06441 bytes = 0;
06442
06443 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06444 *useadsi = 1;
06445 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06446 } else
06447 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06448
06449 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06450 return 0;
06451 }
06452
06453 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06454 {
06455 int x;
06456 if (!ast_adsi_available(chan))
06457 return;
06458 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06459 if (x < 0)
06460 return;
06461 if (!x) {
06462 if (adsi_load_vmail(chan, useadsi)) {
06463 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06464 return;
06465 }
06466 } else
06467 *useadsi = 1;
06468 }
06469
06470 static void adsi_login(struct ast_channel *chan)
06471 {
06472 unsigned char buf[256];
06473 int bytes = 0;
06474 unsigned char keys[8];
06475 int x;
06476 if (!ast_adsi_available(chan))
06477 return;
06478
06479 for (x = 0; x < 8; x++)
06480 keys[x] = 0;
06481
06482 keys[3] = ADSI_KEY_APPS + 3;
06483
06484 bytes += adsi_logo(buf + bytes);
06485 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06486 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06487 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06488 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06489 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06490 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06491 bytes += ast_adsi_set_keys(buf + bytes, keys);
06492 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06493 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06494 }
06495
06496 static void adsi_password(struct ast_channel *chan)
06497 {
06498 unsigned char buf[256];
06499 int bytes = 0;
06500 unsigned char keys[8];
06501 int x;
06502 if (!ast_adsi_available(chan))
06503 return;
06504
06505 for (x = 0; x < 8; x++)
06506 keys[x] = 0;
06507
06508 keys[3] = ADSI_KEY_APPS + 3;
06509
06510 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06511 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06512 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06513 bytes += ast_adsi_set_keys(buf + bytes, keys);
06514 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06515 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06516 }
06517
06518 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06519 {
06520 unsigned char buf[256];
06521 int bytes = 0;
06522 unsigned char keys[8];
06523 int x, y;
06524
06525 if (!ast_adsi_available(chan))
06526 return;
06527
06528 for (x = 0; x < 5; x++) {
06529 y = ADSI_KEY_APPS + 12 + start + x;
06530 if (y > ADSI_KEY_APPS + 12 + 4)
06531 y = 0;
06532 keys[x] = ADSI_KEY_SKT | y;
06533 }
06534 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06535 keys[6] = 0;
06536 keys[7] = 0;
06537
06538 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06539 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06540 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06541 bytes += ast_adsi_set_keys(buf + bytes, keys);
06542 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06543
06544 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06545 }
06546
06547 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06548 {
06549 int bytes = 0;
06550 unsigned char buf[256];
06551 char buf1[256], buf2[256];
06552 char fn2[PATH_MAX];
06553
06554 char cid[256] = "";
06555 char *val;
06556 char *name, *num;
06557 char datetime[21] = "";
06558 FILE *f;
06559
06560 unsigned char keys[8];
06561
06562 int x;
06563
06564 if (!ast_adsi_available(chan))
06565 return;
06566
06567
06568 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06569 f = fopen(fn2, "r");
06570 if (f) {
06571 while (!feof(f)) {
06572 if (!fgets((char *) buf, sizeof(buf), f)) {
06573 continue;
06574 }
06575 if (!feof(f)) {
06576 char *stringp = NULL;
06577 stringp = (char *) buf;
06578 strsep(&stringp, "=");
06579 val = strsep(&stringp, "=");
06580 if (!ast_strlen_zero(val)) {
06581 if (!strcmp((char *) buf, "callerid"))
06582 ast_copy_string(cid, val, sizeof(cid));
06583 if (!strcmp((char *) buf, "origdate"))
06584 ast_copy_string(datetime, val, sizeof(datetime));
06585 }
06586 }
06587 }
06588 fclose(f);
06589 }
06590
06591 for (x = 0; x < 5; x++)
06592 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06593 keys[6] = 0x0;
06594 keys[7] = 0x0;
06595
06596 if (!vms->curmsg) {
06597
06598 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06599 }
06600 if (vms->curmsg >= vms->lastmsg) {
06601
06602 if (vms->curmsg) {
06603
06604 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06605 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06606
06607 } else {
06608
06609 keys[3] = 1;
06610 }
06611 }
06612
06613 if (!ast_strlen_zero(cid)) {
06614 ast_callerid_parse(cid, &name, &num);
06615 if (!name)
06616 name = num;
06617 } else
06618 name = "Unknown Caller";
06619
06620
06621 #ifdef IMAP_STORAGE
06622 ast_mutex_lock(&vms->lock);
06623 #endif
06624 if (vms->deleted[vms->curmsg]) {
06625 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06626 }
06627 #ifdef IMAP_STORAGE
06628 ast_mutex_unlock(&vms->lock);
06629 #endif
06630
06631
06632 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06633 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06634 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06635 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06636
06637 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06638 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06639 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06640 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06641 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06642 bytes += ast_adsi_set_keys(buf + bytes, keys);
06643 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06644
06645 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06646 }
06647
06648 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06649 {
06650 int bytes = 0;
06651 unsigned char buf[256];
06652 unsigned char keys[8];
06653
06654 int x;
06655
06656 if (!ast_adsi_available(chan))
06657 return;
06658
06659
06660 for (x = 0; x < 5; x++)
06661 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06662
06663 keys[6] = 0x0;
06664 keys[7] = 0x0;
06665
06666 if (!vms->curmsg) {
06667
06668 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06669 }
06670 if (vms->curmsg >= vms->lastmsg) {
06671
06672 if (vms->curmsg) {
06673
06674 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06675 } else {
06676
06677 keys[3] = 1;
06678 }
06679 }
06680
06681
06682 #ifdef IMAP_STORAGE
06683 ast_mutex_lock(&vms->lock);
06684 #endif
06685 if (vms->deleted[vms->curmsg]) {
06686 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06687 }
06688 #ifdef IMAP_STORAGE
06689 ast_mutex_unlock(&vms->lock);
06690 #endif
06691
06692
06693 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06694 bytes += ast_adsi_set_keys(buf + bytes, keys);
06695 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06696
06697 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06698 }
06699
06700 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06701 {
06702 unsigned char buf[256] = "";
06703 char buf1[256] = "", buf2[256] = "";
06704 int bytes = 0;
06705 unsigned char keys[8];
06706 int x;
06707
06708 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06709 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06710 if (!ast_adsi_available(chan))
06711 return;
06712 if (vms->newmessages) {
06713 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06714 if (vms->oldmessages) {
06715 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06716 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06717 } else {
06718 snprintf(buf2, sizeof(buf2), "%s.", newm);
06719 }
06720 } else if (vms->oldmessages) {
06721 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06722 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06723 } else {
06724 strcpy(buf1, "You have no messages.");
06725 buf2[0] = ' ';
06726 buf2[1] = '\0';
06727 }
06728 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06729 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06730 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06731
06732 for (x = 0; x < 6; x++)
06733 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06734 keys[6] = 0;
06735 keys[7] = 0;
06736
06737
06738 if (vms->lastmsg < 0)
06739 keys[0] = 1;
06740 bytes += ast_adsi_set_keys(buf + bytes, keys);
06741
06742 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06743
06744 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06745 }
06746
06747 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06748 {
06749 unsigned char buf[256] = "";
06750 char buf1[256] = "", buf2[256] = "";
06751 int bytes = 0;
06752 unsigned char keys[8];
06753 int x;
06754
06755 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06756
06757 if (!ast_adsi_available(chan))
06758 return;
06759
06760
06761 for (x = 0; x < 6; x++)
06762 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06763
06764 keys[6] = 0;
06765 keys[7] = 0;
06766
06767 if ((vms->lastmsg + 1) < 1)
06768 keys[0] = 0;
06769
06770 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06771 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06772
06773 if (vms->lastmsg + 1)
06774 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06775 else
06776 strcpy(buf2, "no messages.");
06777 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06778 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06779 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06780 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06781 bytes += ast_adsi_set_keys(buf + bytes, keys);
06782
06783 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06784
06785 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06786
06787 }
06788
06789
06790
06791
06792
06793
06794
06795
06796
06797
06798
06799
06800
06801
06802
06803 static void adsi_goodbye(struct ast_channel *chan)
06804 {
06805 unsigned char buf[256];
06806 int bytes = 0;
06807
06808 if (!ast_adsi_available(chan))
06809 return;
06810 bytes += adsi_logo(buf + bytes);
06811 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06812 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06813 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06814 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06815
06816 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06817 }
06818
06819
06820
06821
06822
06823 static int get_folder(struct ast_channel *chan, int start)
06824 {
06825 int x;
06826 int d;
06827 char fn[PATH_MAX];
06828 d = ast_play_and_wait(chan, "vm-press");
06829 if (d)
06830 return d;
06831 for (x = start; x < 5; x++) {
06832 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06833 return d;
06834 d = ast_play_and_wait(chan, "vm-for");
06835 if (d)
06836 return d;
06837 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06838
06839
06840
06841
06842 if (x == 0) {
06843 if (ast_fileexists(fn, NULL, NULL)) {
06844 d = vm_play_folder_name(chan, fn);
06845 } else {
06846 ast_verb(1, "failed to find %s\n", fn);
06847 d = vm_play_folder_name(chan, "vm-INBOX");
06848 }
06849 } else {
06850 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06851 d = vm_play_folder_name(chan, fn);
06852 }
06853
06854 if (d)
06855 return d;
06856 d = ast_waitfordigit(chan, 500);
06857 if (d)
06858 return d;
06859 }
06860
06861 d = ast_play_and_wait(chan, "vm-tocancel");
06862 if (d)
06863 return d;
06864 d = ast_waitfordigit(chan, 4000);
06865 return d;
06866 }
06867
06868
06869
06870
06871
06872
06873
06874
06875
06876
06877
06878
06879
06880 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06881 {
06882 int res = 0;
06883 int loops = 0;
06884
06885 res = ast_play_and_wait(chan, fn);
06886 while (((res < '0') || (res > '9')) &&
06887 (res != '#') && (res >= 0) &&
06888 loops < 4) {
06889 res = get_folder(chan, 0);
06890 loops++;
06891 }
06892 if (loops == 4) {
06893 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06894 return '#';
06895 }
06896 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06897 return res;
06898 }
06899
06900
06901
06902
06903
06904
06905
06906
06907
06908
06909
06910
06911
06912
06913
06914
06915
06916
06917
06918 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06919 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06920 {
06921 int cmd = 0;
06922 int retries = 0, prepend_duration = 0, already_recorded = 0;
06923 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06924 char textfile[PATH_MAX];
06925 struct ast_config *msg_cfg;
06926 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06927 #ifndef IMAP_STORAGE
06928 signed char zero_gain = 0;
06929 #endif
06930 const char *duration_str;
06931
06932
06933 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06934 strcpy(textfile, msgfile);
06935 strcpy(backup, msgfile);
06936 strcpy(backup_textfile, msgfile);
06937 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06938 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06939 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06940
06941 if ((msg_cfg = ast_config_load(textfile, config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06942 *duration = atoi(duration_str);
06943 } else {
06944 *duration = 0;
06945 }
06946
06947 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06948 if (cmd)
06949 retries = 0;
06950 switch (cmd) {
06951 case '1':
06952
06953 #ifdef IMAP_STORAGE
06954
06955 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06956 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06957 ast_play_and_wait(chan, INTRO);
06958 ast_play_and_wait(chan, "beep");
06959 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06960 if (cmd == -1) {
06961 break;
06962 }
06963 cmd = 't';
06964 #else
06965
06966
06967
06968 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06969 strcpy(textfile, msgfile);
06970 strncat(textfile, ".txt", sizeof(textfile) - 1);
06971 *duration = 0;
06972
06973
06974 if (!valid_config(msg_cfg)) {
06975 cmd = 0;
06976 break;
06977 }
06978
06979
06980 #ifndef IMAP_STORAGE
06981 if (already_recorded) {
06982 ast_filecopy(backup, msgfile, NULL);
06983 copy(backup_textfile, textfile);
06984 }
06985 else {
06986 ast_filecopy(msgfile, backup, NULL);
06987 copy(textfile, backup_textfile);
06988 }
06989 #endif
06990 already_recorded = 1;
06991
06992 if (record_gain)
06993 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06994
06995 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06996
06997 if (cmd == 'S') {
06998 ast_stream_and_wait(chan, vm_pls_try_again, "");
06999 ast_stream_and_wait(chan, vm_prepend_timeout, "");
07000 ast_filerename(backup, msgfile, NULL);
07001 }
07002
07003 if (record_gain)
07004 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
07005
07006
07007 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
07008 *duration = atoi(duration_str);
07009
07010 if (prepend_duration) {
07011 struct ast_category *msg_cat;
07012
07013 char duration_buf[12];
07014
07015 *duration += prepend_duration;
07016 msg_cat = ast_category_get(msg_cfg, "message");
07017 snprintf(duration_buf, 11, "%ld", *duration);
07018 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
07019 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
07020 }
07021 }
07022
07023 #endif
07024 break;
07025 case '2':
07026
07027 #ifdef IMAP_STORAGE
07028 *vms->introfn = '\0';
07029 #endif
07030 cmd = 't';
07031 break;
07032 case '*':
07033 cmd = '*';
07034 break;
07035 default:
07036
07037 already_recorded = 0;
07038
07039 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
07040
07041 if (!cmd) {
07042 cmd = ast_play_and_wait(chan, "vm-starmain");
07043
07044 }
07045 if (!cmd) {
07046 cmd = ast_waitfordigit(chan, 6000);
07047 }
07048 if (!cmd) {
07049 retries++;
07050 }
07051 if (retries > 3) {
07052 cmd = '*';
07053 }
07054 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07055 }
07056 }
07057
07058 if (valid_config(msg_cfg))
07059 ast_config_destroy(msg_cfg);
07060 if (prepend_duration)
07061 *duration = prepend_duration;
07062
07063 if (already_recorded && cmd == -1) {
07064
07065 ast_filerename(backup, msgfile, NULL);
07066 rename(backup_textfile, textfile);
07067 }
07068
07069 if (cmd == 't' || cmd == 'S')
07070 cmd = 0;
07071 return cmd;
07072 }
07073
07074 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07075 {
07076 struct ast_event *event;
07077 char *mailbox, *context;
07078
07079
07080 context = mailbox = ast_strdupa(box);
07081 strsep(&context, "@");
07082 if (ast_strlen_zero(context))
07083 context = "default";
07084
07085 if (!(event = ast_event_new(AST_EVENT_MWI,
07086 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07087 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07088 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07089 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07090 AST_EVENT_IE_END))) {
07091 return;
07092 }
07093
07094 ast_event_queue_and_cache(event);
07095 }
07096
07097
07098
07099
07100
07101
07102
07103
07104
07105
07106
07107
07108
07109
07110
07111 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)
07112 {
07113 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07114 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07115 const char *category;
07116 char *myserveremail = serveremail;
07117
07118 ast_channel_lock(chan);
07119 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07120 category = ast_strdupa(category);
07121 }
07122 ast_channel_unlock(chan);
07123
07124 #ifndef IMAP_STORAGE
07125 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07126 #else
07127 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07128 #endif
07129 make_file(fn, sizeof(fn), todir, msgnum);
07130 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07131
07132 if (!ast_strlen_zero(vmu->attachfmt)) {
07133 if (strstr(fmt, vmu->attachfmt))
07134 fmt = vmu->attachfmt;
07135 else
07136 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);
07137 }
07138
07139
07140 fmt = ast_strdupa(fmt);
07141 stringp = fmt;
07142 strsep(&stringp, "|");
07143
07144 if (!ast_strlen_zero(vmu->serveremail))
07145 myserveremail = vmu->serveremail;
07146
07147 if (!ast_strlen_zero(vmu->email)) {
07148 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07149
07150 if (attach_user_voicemail)
07151 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07152
07153
07154 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07155
07156 if (attach_user_voicemail)
07157 DISPOSE(todir, msgnum);
07158 }
07159
07160 if (!ast_strlen_zero(vmu->pager)) {
07161 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07162 }
07163
07164 if (ast_test_flag(vmu, VM_DELETE))
07165 DELETE(todir, msgnum, fn, vmu);
07166
07167
07168 if (ast_app_has_voicemail(ext_context, NULL))
07169 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07170
07171 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07172
07173 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);
07174 run_externnotify(vmu->context, vmu->mailbox, flag);
07175
07176 #ifdef IMAP_STORAGE
07177 vm_delete(fn);
07178 if (ast_test_flag(vmu, VM_DELETE)) {
07179 vm_imap_delete(NULL, vms->curmsg, vmu);
07180 vms->newmessages--;
07181 }
07182 #endif
07183
07184 return 0;
07185 }
07186
07187
07188
07189
07190
07191
07192
07193
07194
07195
07196
07197
07198
07199
07200
07201
07202
07203
07204
07205
07206
07207
07208
07209
07210
07211
07212
07213
07214 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)
07215 {
07216 #ifdef IMAP_STORAGE
07217 int todircount = 0;
07218 struct vm_state *dstvms;
07219 #endif
07220 char username[70]="";
07221 char fn[PATH_MAX];
07222 char ecodes[16] = "#";
07223 int res = 0, cmd = 0;
07224 struct ast_vm_user *receiver = NULL, *vmtmp;
07225 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07226 char *stringp;
07227 const char *s;
07228 int saved_messages = 0;
07229 int valid_extensions = 0;
07230 char *dir;
07231 int curmsg;
07232 char urgent_str[7] = "";
07233 int prompt_played = 0;
07234 #ifndef IMAP_STORAGE
07235 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07236 #endif
07237 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07238 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07239 }
07240
07241 if (vms == NULL) return -1;
07242 dir = vms->curdir;
07243 curmsg = vms->curmsg;
07244
07245 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07246 while (!res && !valid_extensions) {
07247 int use_directory = 0;
07248 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07249 int done = 0;
07250 int retries = 0;
07251 cmd = 0;
07252 while ((cmd >= 0) && !done ){
07253 if (cmd)
07254 retries = 0;
07255 switch (cmd) {
07256 case '1':
07257 use_directory = 0;
07258 done = 1;
07259 break;
07260 case '2':
07261 use_directory = 1;
07262 done = 1;
07263 break;
07264 case '*':
07265 cmd = 't';
07266 done = 1;
07267 break;
07268 default:
07269
07270 cmd = ast_play_and_wait(chan, "vm-forward");
07271 if (!cmd) {
07272 cmd = ast_waitfordigit(chan, 3000);
07273 }
07274 if (!cmd) {
07275 retries++;
07276 }
07277 if (retries > 3) {
07278 cmd = 't';
07279 done = 1;
07280 }
07281 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07282 }
07283 }
07284 if (cmd < 0 || cmd == 't')
07285 break;
07286 }
07287
07288 if (use_directory) {
07289
07290
07291 char old_context[sizeof(chan->context)];
07292 char old_exten[sizeof(chan->exten)];
07293 int old_priority;
07294 struct ast_app* directory_app;
07295
07296 directory_app = pbx_findapp("Directory");
07297 if (directory_app) {
07298 char vmcontext[256];
07299
07300 memcpy(old_context, chan->context, sizeof(chan->context));
07301 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07302 old_priority = chan->priority;
07303
07304
07305 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07306 res = pbx_exec(chan, directory_app, vmcontext);
07307
07308 ast_copy_string(username, chan->exten, sizeof(username));
07309
07310
07311 memcpy(chan->context, old_context, sizeof(chan->context));
07312 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07313 chan->priority = old_priority;
07314 } else {
07315 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07316 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07317 }
07318 } else {
07319
07320 res = ast_streamfile(chan, "vm-extension", chan->language);
07321 prompt_played++;
07322 if (res || prompt_played > 4)
07323 break;
07324 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07325 break;
07326 }
07327
07328
07329 if (ast_strlen_zero(username))
07330 continue;
07331 stringp = username;
07332 s = strsep(&stringp, "*");
07333
07334 valid_extensions = 1;
07335 while (s) {
07336 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07337 int oldmsgs;
07338 int newmsgs;
07339 int capacity;
07340 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07341 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07342
07343 res = ast_play_and_wait(chan, "pbx-invalid");
07344 valid_extensions = 0;
07345 break;
07346 }
07347 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07348 if ((newmsgs + oldmsgs) >= capacity) {
07349 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07350 res = ast_play_and_wait(chan, "vm-mailboxfull");
07351 valid_extensions = 0;
07352 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07353 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07354 free_user(vmtmp);
07355 }
07356 inprocess_count(receiver->mailbox, receiver->context, -1);
07357 break;
07358 }
07359 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07360 } else {
07361
07362
07363
07364
07365
07366 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07367 free_user(receiver);
07368 }
07369 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07370
07371 res = ast_play_and_wait(chan, "pbx-invalid");
07372 valid_extensions = 0;
07373 break;
07374 }
07375
07376
07377 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07378 RETRIEVE(fn, -1, s, receiver->context);
07379 if (ast_fileexists(fn, NULL, NULL) > 0) {
07380 res = ast_stream_and_wait(chan, fn, ecodes);
07381 if (res) {
07382 DISPOSE(fn, -1);
07383 return res;
07384 }
07385 } else {
07386 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07387 }
07388 DISPOSE(fn, -1);
07389
07390 s = strsep(&stringp, "*");
07391 }
07392
07393 if (valid_extensions)
07394 break;
07395 }
07396
07397 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07398 return res;
07399 if (is_new_message == 1) {
07400 struct leave_vm_options leave_options;
07401 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07402 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07403
07404
07405 memset(&leave_options, 0, sizeof(leave_options));
07406 leave_options.record_gain = record_gain;
07407 cmd = leave_voicemail(chan, mailbox, &leave_options);
07408 } else {
07409
07410 long duration = 0;
07411 struct vm_state vmstmp;
07412 int copy_msg_result = 0;
07413 memcpy(&vmstmp, vms, sizeof(vmstmp));
07414
07415 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07416
07417 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07418 if (!cmd) {
07419 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07420 #ifdef IMAP_STORAGE
07421 int attach_user_voicemail;
07422 char *myserveremail = serveremail;
07423
07424
07425 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07426 if (!dstvms) {
07427 dstvms = create_vm_state_from_user(vmtmp);
07428 }
07429 if (dstvms) {
07430 init_mailstream(dstvms, 0);
07431 if (!dstvms->mailstream) {
07432 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07433 } else {
07434 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07435 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07436 }
07437 } else {
07438 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07439 }
07440 if (!ast_strlen_zero(vmtmp->serveremail))
07441 myserveremail = vmtmp->serveremail;
07442 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07443
07444 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07445 dstvms->curbox,
07446 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07447 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07448 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07449 NULL, urgent_str);
07450 #else
07451 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07452 #endif
07453 saved_messages++;
07454 AST_LIST_REMOVE_CURRENT(list);
07455 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07456 free_user(vmtmp);
07457 if (res)
07458 break;
07459 }
07460 AST_LIST_TRAVERSE_SAFE_END;
07461 if (saved_messages > 0 && !copy_msg_result) {
07462
07463
07464
07465
07466
07467
07468
07469
07470 #ifdef IMAP_STORAGE
07471
07472 if (ast_strlen_zero(vmstmp.introfn))
07473 #endif
07474 res = ast_play_and_wait(chan, "vm-msgsaved");
07475 }
07476 #ifndef IMAP_STORAGE
07477 else {
07478
07479 res = ast_play_and_wait(chan, "vm-mailboxfull");
07480 }
07481
07482 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07483 strcpy(textfile, msgfile);
07484 strcpy(backup, msgfile);
07485 strcpy(backup_textfile, msgfile);
07486 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07487 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07488 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07489 if (ast_fileexists(backup, NULL, NULL) > 0) {
07490 ast_filerename(backup, msgfile, NULL);
07491 rename(backup_textfile, textfile);
07492 }
07493 #endif
07494 }
07495 DISPOSE(dir, curmsg);
07496 #ifndef IMAP_STORAGE
07497 if (cmd) {
07498 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07499 strcpy(textfile, msgfile);
07500 strcpy(backup_textfile, msgfile);
07501 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07502 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07503 rename(backup_textfile, textfile);
07504 }
07505 #endif
07506 }
07507
07508
07509 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07510 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07511 free_user(vmtmp);
07512 }
07513 return res ? res : cmd;
07514 }
07515
07516 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07517 {
07518 int res;
07519 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07520 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07521 return res;
07522 }
07523
07524 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07525 {
07526 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07527 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);
07528 }
07529
07530 static int play_message_category(struct ast_channel *chan, const char *category)
07531 {
07532 int res = 0;
07533
07534 if (!ast_strlen_zero(category))
07535 res = ast_play_and_wait(chan, category);
07536
07537 if (res) {
07538 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07539 res = 0;
07540 }
07541
07542 return res;
07543 }
07544
07545 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07546 {
07547 int res = 0;
07548 struct vm_zone *the_zone = NULL;
07549 time_t t;
07550
07551 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07552 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07553 return 0;
07554 }
07555
07556
07557 if (!ast_strlen_zero(vmu->zonetag)) {
07558
07559 struct vm_zone *z;
07560 AST_LIST_LOCK(&zones);
07561 AST_LIST_TRAVERSE(&zones, z, list) {
07562 if (!strcmp(z->name, vmu->zonetag)) {
07563 the_zone = z;
07564 break;
07565 }
07566 }
07567 AST_LIST_UNLOCK(&zones);
07568 }
07569
07570
07571 #if 0
07572
07573 ast_localtime(&t, &time_now, NULL);
07574 tv_now = ast_tvnow();
07575 ast_localtime(&tv_now, &time_then, NULL);
07576
07577
07578 if (time_now.tm_year == time_then.tm_year)
07579 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07580 else
07581 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07582 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07583
07584
07585 #endif
07586 if (the_zone) {
07587 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07588 } else if (!strncasecmp(chan->language, "de", 2)) {
07589 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07590 } else if (!strncasecmp(chan->language, "gr", 2)) {
07591 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07592 } else if (!strncasecmp(chan->language, "it", 2)) {
07593 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);
07594 } else if (!strncasecmp(chan->language, "nl", 2)) {
07595 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07596 } else if (!strncasecmp(chan->language, "no", 2)) {
07597 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07598 } else if (!strncasecmp(chan->language, "pl", 2)) {
07599 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07600 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07601 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);
07602 } else if (!strncasecmp(chan->language, "se", 2)) {
07603 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07604 } else if (!strncasecmp(chan->language, "zh", 2)) {
07605 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07606 } else if (!strncasecmp(chan->language, "vi", 2)) {
07607 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);
07608 } else {
07609 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07610 }
07611 #if 0
07612 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07613 #endif
07614 return res;
07615 }
07616
07617
07618
07619 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07620 {
07621 int res = 0;
07622 int i;
07623 char *callerid, *name;
07624 char prefile[PATH_MAX] = "";
07625
07626
07627
07628
07629
07630
07631
07632
07633
07634 if ((cid == NULL)||(context == NULL))
07635 return res;
07636
07637
07638 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07639 ast_callerid_parse(cid, &name, &callerid);
07640 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07641
07642
07643 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07644 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07645 if ((strcmp(cidinternalcontexts[i], context) == 0))
07646 break;
07647 }
07648 if (i != MAX_NUM_CID_CONTEXTS){
07649 if (!res) {
07650 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07651 if (!ast_strlen_zero(prefile)) {
07652
07653 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07654 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07655 if (!callback)
07656 res = wait_file2(chan, vms, "vm-from");
07657 res = ast_stream_and_wait(chan, prefile, "");
07658 } else {
07659 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07660
07661 if (!callback)
07662 res = wait_file2(chan, vms, "vm-from-extension");
07663 res = ast_say_digit_str(chan, callerid, "", chan->language);
07664 }
07665 }
07666 }
07667 } else if (!res) {
07668 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07669
07670 if (!callback)
07671 res = wait_file2(chan, vms, "vm-from-phonenumber");
07672 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07673 }
07674 } else {
07675
07676 ast_debug(1, "VM-CID: From an unknown number\n");
07677
07678 res = wait_file2(chan, vms, "vm-unknown-caller");
07679 }
07680 return res;
07681 }
07682
07683 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07684 {
07685 int res = 0;
07686 int durationm;
07687 int durations;
07688
07689 if (duration == NULL)
07690 return res;
07691
07692
07693 durations = atoi(duration);
07694 durationm = (durations / 60);
07695
07696 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07697
07698 if ((!res) && (durationm >= minduration)) {
07699 res = wait_file2(chan, vms, "vm-duration");
07700
07701
07702 if (!strncasecmp(chan->language, "pl", 2)) {
07703 div_t num = div(durationm, 10);
07704
07705 if (durationm == 1) {
07706 res = ast_play_and_wait(chan, "digits/1z");
07707 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07708 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07709 if (num.rem == 2) {
07710 if (!num.quot) {
07711 res = ast_play_and_wait(chan, "digits/2-ie");
07712 } else {
07713 res = say_and_wait(chan, durationm - 2 , chan->language);
07714 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07715 }
07716 } else {
07717 res = say_and_wait(chan, durationm, chan->language);
07718 }
07719 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07720 } else {
07721 res = say_and_wait(chan, durationm, chan->language);
07722 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07723 }
07724
07725 } else {
07726 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07727 res = wait_file2(chan, vms, "vm-minutes");
07728 }
07729 }
07730 return res;
07731 }
07732
07733 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07734 {
07735 int res = 0;
07736 char filename[256], *cid;
07737 const char *origtime, *context, *category, *duration, *flag;
07738 struct ast_config *msg_cfg;
07739 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07740
07741 vms->starting = 0;
07742 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07743 adsi_message(chan, vms);
07744 if (!vms->curmsg) {
07745 res = wait_file2(chan, vms, "vm-first");
07746 } else if (vms->curmsg == vms->lastmsg) {
07747 res = wait_file2(chan, vms, "vm-last");
07748 }
07749
07750 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07751 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07752 msg_cfg = ast_config_load(filename, config_flags);
07753 if (!valid_config(msg_cfg)) {
07754 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07755 return 0;
07756 }
07757 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07758
07759
07760 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07761 res = wait_file2(chan, vms, "vm-Urgent");
07762 }
07763
07764 if (!res) {
07765
07766
07767 if (!strncasecmp(chan->language, "pl", 2)) {
07768 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07769 int ten, one;
07770 char nextmsg[256];
07771 ten = (vms->curmsg + 1) / 10;
07772 one = (vms->curmsg + 1) % 10;
07773
07774 if (vms->curmsg < 20) {
07775 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07776 res = wait_file2(chan, vms, nextmsg);
07777 } else {
07778 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07779 res = wait_file2(chan, vms, nextmsg);
07780 if (one > 0) {
07781 if (!res) {
07782 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07783 res = wait_file2(chan, vms, nextmsg);
07784 }
07785 }
07786 }
07787 }
07788 if (!res)
07789 res = wait_file2(chan, vms, "vm-message");
07790
07791 } else if (!strncasecmp(chan->language, "he", 2)) {
07792 if (!vms->curmsg) {
07793 res = wait_file2(chan, vms, "vm-message");
07794 res = wait_file2(chan, vms, "vm-first");
07795 } else if (vms->curmsg == vms->lastmsg) {
07796 res = wait_file2(chan, vms, "vm-message");
07797 res = wait_file2(chan, vms, "vm-last");
07798 } else {
07799 res = wait_file2(chan, vms, "vm-message");
07800 res = wait_file2(chan, vms, "vm-number");
07801 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07802 }
07803
07804 } else if (!strncasecmp(chan->language, "vi", 2)) {
07805 if (!vms->curmsg) {
07806 res = wait_file2(chan, vms, "vm-message");
07807 res = wait_file2(chan, vms, "vm-first");
07808 } else if (vms->curmsg == vms->lastmsg) {
07809 res = wait_file2(chan, vms, "vm-message");
07810 res = wait_file2(chan, vms, "vm-last");
07811 } else {
07812 res = wait_file2(chan, vms, "vm-message");
07813 res = wait_file2(chan, vms, "vm-number");
07814 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07815 }
07816 } else {
07817 if (!strncasecmp(chan->language, "se", 2)) {
07818 res = wait_file2(chan, vms, "vm-meddelandet");
07819 } else {
07820 res = wait_file2(chan, vms, "vm-message");
07821 }
07822 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07823 if (!res) {
07824 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07825 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07826 }
07827 }
07828 }
07829 }
07830
07831 if (!valid_config(msg_cfg)) {
07832 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07833 return 0;
07834 }
07835
07836 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07837 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07838 DISPOSE(vms->curdir, vms->curmsg);
07839 ast_config_destroy(msg_cfg);
07840 return 0;
07841 }
07842
07843 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07844 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07845 category = ast_variable_retrieve(msg_cfg, "message", "category");
07846
07847 context = ast_variable_retrieve(msg_cfg, "message", "context");
07848 if (!strncasecmp("macro", context, 5))
07849 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07850 if (!res) {
07851 res = play_message_category(chan, category);
07852 }
07853 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07854 res = play_message_datetime(chan, vmu, origtime, filename);
07855 }
07856 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07857 res = play_message_callerid(chan, vms, cid, context, 0);
07858 }
07859 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07860 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07861 }
07862
07863 if (res == '1') {
07864 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07865 res = 0;
07866 }
07867 ast_config_destroy(msg_cfg);
07868
07869 if (!res) {
07870 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07871 #ifdef IMAP_STORAGE
07872 ast_mutex_lock(&vms->lock);
07873 #endif
07874 vms->heard[vms->curmsg] = 1;
07875 #ifdef IMAP_STORAGE
07876 ast_mutex_unlock(&vms->lock);
07877
07878
07879
07880 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07881 wait_file(chan, vms, vms->introfn);
07882 }
07883 #endif
07884 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07885 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07886 res = 0;
07887 }
07888 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07889 }
07890 DISPOSE(vms->curdir, vms->curmsg);
07891 return res;
07892 }
07893
07894 #ifdef IMAP_STORAGE
07895 static int imap_remove_file(char *dir, int msgnum)
07896 {
07897 char fn[PATH_MAX];
07898 char full_fn[PATH_MAX];
07899 char intro[PATH_MAX] = {0,};
07900
07901 if (msgnum > -1) {
07902 make_file(fn, sizeof(fn), dir, msgnum);
07903 snprintf(intro, sizeof(intro), "%sintro", fn);
07904 } else
07905 ast_copy_string(fn, dir, sizeof(fn));
07906
07907 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07908 ast_filedelete(fn, NULL);
07909 if (!ast_strlen_zero(intro)) {
07910 ast_filedelete(intro, NULL);
07911 }
07912 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07913 unlink(full_fn);
07914 }
07915 return 0;
07916 }
07917
07918
07919
07920 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07921 {
07922 char *file, *filename;
07923 char *attachment;
07924 char arg[10];
07925 int i;
07926 BODY* body;
07927
07928 file = strrchr(ast_strdupa(dir), '/');
07929 if (file) {
07930 *file++ = '\0';
07931 } else {
07932 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07933 return -1;
07934 }
07935
07936 ast_mutex_lock(&vms->lock);
07937 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07938 mail_fetchstructure(vms->mailstream, i + 1, &body);
07939
07940 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07941 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07942 } else {
07943 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07944 ast_mutex_unlock(&vms->lock);
07945 return -1;
07946 }
07947 filename = strsep(&attachment, ".");
07948 if (!strcmp(filename, file)) {
07949 sprintf(arg, "%d", i + 1);
07950 mail_setflag(vms->mailstream, arg, "\\DELETED");
07951 }
07952 }
07953 mail_expunge(vms->mailstream);
07954 ast_mutex_unlock(&vms->lock);
07955 return 0;
07956 }
07957
07958 #elif !defined(IMAP_STORAGE)
07959 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07960 {
07961 int count_msg, last_msg;
07962
07963 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07964
07965
07966
07967
07968 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07969
07970
07971 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07972
07973
07974 count_msg = count_messages(vmu, vms->curdir);
07975 if (count_msg < 0) {
07976 return count_msg;
07977 } else {
07978 vms->lastmsg = count_msg - 1;
07979 }
07980
07981 if (vm_allocate_dh(vms, vmu, count_msg)) {
07982 return -1;
07983 }
07984
07985
07986
07987
07988
07989
07990
07991
07992 if (vm_lock_path(vms->curdir)) {
07993 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07994 return ERROR_LOCK_PATH;
07995 }
07996
07997
07998 last_msg = last_message_index(vmu, vms->curdir);
07999 ast_unlock_path(vms->curdir);
08000
08001 if (last_msg < -1) {
08002 return last_msg;
08003 } else if (vms->lastmsg != last_msg) {
08004 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);
08005 resequence_mailbox(vmu, vms->curdir, count_msg);
08006 }
08007
08008 return 0;
08009 }
08010 #endif
08011
08012 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
08013 {
08014 int x = 0;
08015 int last_msg_idx = 0;
08016
08017 #ifndef IMAP_STORAGE
08018 int res = 0, nummsg;
08019 char fn2[PATH_MAX];
08020 #endif
08021
08022 if (vms->lastmsg <= -1) {
08023 goto done;
08024 }
08025
08026 vms->curmsg = -1;
08027 #ifndef IMAP_STORAGE
08028
08029 if (vm_lock_path(vms->curdir)) {
08030 return ERROR_LOCK_PATH;
08031 }
08032
08033
08034 last_msg_idx = last_message_index(vmu, vms->curdir);
08035 if (last_msg_idx != vms->lastmsg) {
08036 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
08037 }
08038
08039
08040 for (x = 0; x < last_msg_idx + 1; x++) {
08041 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
08042
08043 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08044 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
08045 break;
08046 }
08047 vms->curmsg++;
08048 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08049 if (strcmp(vms->fn, fn2)) {
08050 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08051 }
08052 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08053
08054 res = save_to_folder(vmu, vms, x, 1);
08055 if (res == ERROR_LOCK_PATH) {
08056
08057 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08058 vms->deleted[x] = 0;
08059 vms->heard[x] = 0;
08060 --x;
08061 }
08062 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08063
08064 res = save_to_folder(vmu, vms, x, 10);
08065 if (res == ERROR_LOCK_PATH) {
08066
08067 vms->deleted[x] = 0;
08068 vms->heard[x] = 0;
08069 --x;
08070 }
08071 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08072
08073
08074 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08075 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08076 DELETE(vms->curdir, x, vms->fn, vmu);
08077 }
08078 }
08079 }
08080
08081
08082 nummsg = x - 1;
08083 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08084 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08085 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08086 DELETE(vms->curdir, x, vms->fn, vmu);
08087 }
08088 }
08089 ast_unlock_path(vms->curdir);
08090 #else
08091 ast_mutex_lock(&vms->lock);
08092 if (vms->deleted) {
08093
08094
08095 last_msg_idx = vms->dh_arraysize;
08096 for (x = last_msg_idx - 1; x >= 0; x--) {
08097 if (vms->deleted[x]) {
08098 ast_debug(3, "IMAP delete of %d\n", x);
08099 DELETE(vms->curdir, x, vms->fn, vmu);
08100 }
08101 }
08102 }
08103 #endif
08104
08105 done:
08106 if (vms->deleted) {
08107 ast_free(vms->deleted);
08108 vms->deleted = NULL;
08109 }
08110 if (vms->heard) {
08111 ast_free(vms->heard);
08112 vms->heard = NULL;
08113 }
08114 vms->dh_arraysize = 0;
08115 #ifdef IMAP_STORAGE
08116 ast_mutex_unlock(&vms->lock);
08117 #endif
08118
08119 return 0;
08120 }
08121
08122
08123
08124
08125
08126
08127
08128 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08129 {
08130 int cmd;
08131 char *buf;
08132
08133 buf = ast_alloca(strlen(box) + 2);
08134 strcpy(buf, box);
08135 strcat(buf, "s");
08136
08137 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08138 cmd = ast_play_and_wait(chan, buf);
08139 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08140 } else {
08141 cmd = ast_play_and_wait(chan, "vm-messages");
08142 return cmd ? cmd : ast_play_and_wait(chan, box);
08143 }
08144 }
08145
08146 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08147 {
08148 int cmd;
08149
08150 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08151 if (!strcasecmp(box, "vm-INBOX"))
08152 cmd = ast_play_and_wait(chan, "vm-new-e");
08153 else
08154 cmd = ast_play_and_wait(chan, "vm-old-e");
08155 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08156 } else {
08157 cmd = ast_play_and_wait(chan, "vm-messages");
08158 return cmd ? cmd : ast_play_and_wait(chan, box);
08159 }
08160 }
08161
08162 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08163 {
08164 int cmd;
08165
08166 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08167 cmd = ast_play_and_wait(chan, "vm-messages");
08168 return cmd ? cmd : ast_play_and_wait(chan, box);
08169 } else {
08170 cmd = ast_play_and_wait(chan, box);
08171 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08172 }
08173 }
08174
08175 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08176 {
08177 int cmd;
08178
08179 if ( !strncasecmp(chan->language, "it", 2) ||
08180 !strncasecmp(chan->language, "es", 2) ||
08181 !strncasecmp(chan->language, "pt", 2)) {
08182 cmd = ast_play_and_wait(chan, "vm-messages");
08183 return cmd ? cmd : ast_play_and_wait(chan, box);
08184 } else if (!strncasecmp(chan->language, "gr", 2)) {
08185 return vm_play_folder_name_gr(chan, box);
08186 } else if (!strncasecmp(chan->language, "he", 2)) {
08187 return ast_play_and_wait(chan, box);
08188 } else if (!strncasecmp(chan->language, "pl", 2)) {
08189 return vm_play_folder_name_pl(chan, box);
08190 } else if (!strncasecmp(chan->language, "ua", 2)) {
08191 return vm_play_folder_name_ua(chan, box);
08192 } else if (!strncasecmp(chan->language, "vi", 2)) {
08193 return ast_play_and_wait(chan, box);
08194 } else {
08195 cmd = ast_play_and_wait(chan, box);
08196 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08197 }
08198 }
08199
08200
08201
08202
08203
08204
08205
08206
08207
08208
08209
08210
08211
08212 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08213 {
08214 int res = 0;
08215
08216 if (vms->newmessages) {
08217 res = ast_play_and_wait(chan, "vm-youhave");
08218 if (!res)
08219 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08220 if (!res) {
08221 if ((vms->newmessages == 1)) {
08222 res = ast_play_and_wait(chan, "vm-INBOX");
08223 if (!res)
08224 res = ast_play_and_wait(chan, "vm-message");
08225 } else {
08226 res = ast_play_and_wait(chan, "vm-INBOXs");
08227 if (!res)
08228 res = ast_play_and_wait(chan, "vm-messages");
08229 }
08230 }
08231 } else if (vms->oldmessages){
08232 res = ast_play_and_wait(chan, "vm-youhave");
08233 if (!res)
08234 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08235 if ((vms->oldmessages == 1)){
08236 res = ast_play_and_wait(chan, "vm-Old");
08237 if (!res)
08238 res = ast_play_and_wait(chan, "vm-message");
08239 } else {
08240 res = ast_play_and_wait(chan, "vm-Olds");
08241 if (!res)
08242 res = ast_play_and_wait(chan, "vm-messages");
08243 }
08244 } else if (!vms->oldmessages && !vms->newmessages)
08245 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08246 return res;
08247 }
08248
08249
08250
08251
08252
08253
08254
08255
08256
08257
08258
08259
08260
08261
08262
08263
08264
08265
08266
08267
08268
08269
08270
08271
08272
08273
08274
08275
08276
08277
08278
08279
08280
08281
08282
08283
08284
08285
08286
08287
08288
08289
08290
08291
08292
08293
08294
08295
08296
08297
08298
08299
08300
08301
08302
08303
08304
08305
08306 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08307 {
08308 int res;
08309 int lastnum = 0;
08310
08311 res = ast_play_and_wait(chan, "vm-youhave");
08312
08313 if (!res && vms->newmessages) {
08314 lastnum = vms->newmessages;
08315
08316 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08317 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08318 }
08319
08320 if (!res && vms->oldmessages) {
08321 res = ast_play_and_wait(chan, "vm-and");
08322 }
08323 }
08324
08325 if (!res && vms->oldmessages) {
08326 lastnum = vms->oldmessages;
08327
08328 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08329 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08330 }
08331 }
08332
08333 if (!res) {
08334 if (lastnum == 0) {
08335 res = ast_play_and_wait(chan, "vm-no");
08336 }
08337 if (!res) {
08338 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08339 }
08340 }
08341
08342 return res;
08343 }
08344
08345
08346 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08347 {
08348 int res = 0;
08349
08350
08351 if (!res) {
08352 if ((vms->newmessages) || (vms->oldmessages)) {
08353 res = ast_play_and_wait(chan, "vm-youhave");
08354 }
08355
08356
08357
08358
08359
08360 if (vms->newmessages) {
08361 if (!res) {
08362 if (vms->newmessages == 1) {
08363 res = ast_play_and_wait(chan, "vm-INBOX1");
08364 } else {
08365 if (vms->newmessages == 2) {
08366 res = ast_play_and_wait(chan, "vm-shtei");
08367 } else {
08368 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08369 }
08370 res = ast_play_and_wait(chan, "vm-INBOX");
08371 }
08372 }
08373 if (vms->oldmessages && !res) {
08374 res = ast_play_and_wait(chan, "vm-and");
08375 if (vms->oldmessages == 1) {
08376 res = ast_play_and_wait(chan, "vm-Old1");
08377 } else {
08378 if (vms->oldmessages == 2) {
08379 res = ast_play_and_wait(chan, "vm-shtei");
08380 } else {
08381 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08382 }
08383 res = ast_play_and_wait(chan, "vm-Old");
08384 }
08385 }
08386 }
08387 if (!res && vms->oldmessages && !vms->newmessages) {
08388 if (!res) {
08389 if (vms->oldmessages == 1) {
08390 res = ast_play_and_wait(chan, "vm-Old1");
08391 } else {
08392 if (vms->oldmessages == 2) {
08393 res = ast_play_and_wait(chan, "vm-shtei");
08394 } else {
08395 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08396 }
08397 res = ast_play_and_wait(chan, "vm-Old");
08398 }
08399 }
08400 }
08401 if (!res) {
08402 if (!vms->oldmessages && !vms->newmessages) {
08403 if (!res) {
08404 res = ast_play_and_wait(chan, "vm-nomessages");
08405 }
08406 }
08407 }
08408 }
08409 return res;
08410 }
08411
08412
08413 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08414 {
08415 int res;
08416
08417
08418 res = ast_play_and_wait(chan, "vm-youhave");
08419 if (!res) {
08420 if (vms->urgentmessages) {
08421 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08422 if (!res)
08423 res = ast_play_and_wait(chan, "vm-Urgent");
08424 if ((vms->oldmessages || vms->newmessages) && !res) {
08425 res = ast_play_and_wait(chan, "vm-and");
08426 } else if (!res) {
08427 if ((vms->urgentmessages == 1))
08428 res = ast_play_and_wait(chan, "vm-message");
08429 else
08430 res = ast_play_and_wait(chan, "vm-messages");
08431 }
08432 }
08433 if (vms->newmessages) {
08434 res = say_and_wait(chan, vms->newmessages, chan->language);
08435 if (!res)
08436 res = ast_play_and_wait(chan, "vm-INBOX");
08437 if (vms->oldmessages && !res)
08438 res = ast_play_and_wait(chan, "vm-and");
08439 else if (!res) {
08440 if ((vms->newmessages == 1))
08441 res = ast_play_and_wait(chan, "vm-message");
08442 else
08443 res = ast_play_and_wait(chan, "vm-messages");
08444 }
08445
08446 }
08447 if (!res && vms->oldmessages) {
08448 res = say_and_wait(chan, vms->oldmessages, chan->language);
08449 if (!res)
08450 res = ast_play_and_wait(chan, "vm-Old");
08451 if (!res) {
08452 if (vms->oldmessages == 1)
08453 res = ast_play_and_wait(chan, "vm-message");
08454 else
08455 res = ast_play_and_wait(chan, "vm-messages");
08456 }
08457 }
08458 if (!res) {
08459 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08460 res = ast_play_and_wait(chan, "vm-no");
08461 if (!res)
08462 res = ast_play_and_wait(chan, "vm-messages");
08463 }
08464 }
08465 }
08466 return res;
08467 }
08468
08469
08470 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08471 {
08472
08473 int res;
08474 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08475 res = ast_play_and_wait(chan, "vm-no") ||
08476 ast_play_and_wait(chan, "vm-message");
08477 else
08478 res = ast_play_and_wait(chan, "vm-youhave");
08479 if (!res && vms->newmessages) {
08480 res = (vms->newmessages == 1) ?
08481 ast_play_and_wait(chan, "digits/un") ||
08482 ast_play_and_wait(chan, "vm-nuovo") ||
08483 ast_play_and_wait(chan, "vm-message") :
08484
08485 say_and_wait(chan, vms->newmessages, chan->language) ||
08486 ast_play_and_wait(chan, "vm-nuovi") ||
08487 ast_play_and_wait(chan, "vm-messages");
08488 if (!res && vms->oldmessages)
08489 res = ast_play_and_wait(chan, "vm-and");
08490 }
08491 if (!res && vms->oldmessages) {
08492 res = (vms->oldmessages == 1) ?
08493 ast_play_and_wait(chan, "digits/un") ||
08494 ast_play_and_wait(chan, "vm-vecchio") ||
08495 ast_play_and_wait(chan, "vm-message") :
08496
08497 say_and_wait(chan, vms->oldmessages, chan->language) ||
08498 ast_play_and_wait(chan, "vm-vecchi") ||
08499 ast_play_and_wait(chan, "vm-messages");
08500 }
08501 return res;
08502 }
08503
08504
08505 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08506 {
08507
08508 int res;
08509 div_t num;
08510
08511 if (!vms->oldmessages && !vms->newmessages) {
08512 res = ast_play_and_wait(chan, "vm-no");
08513 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08514 return res;
08515 } else {
08516 res = ast_play_and_wait(chan, "vm-youhave");
08517 }
08518
08519 if (vms->newmessages) {
08520 num = div(vms->newmessages, 10);
08521 if (vms->newmessages == 1) {
08522 res = ast_play_and_wait(chan, "digits/1-a");
08523 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08524 res = res ? res : ast_play_and_wait(chan, "vm-message");
08525 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08526 if (num.rem == 2) {
08527 if (!num.quot) {
08528 res = ast_play_and_wait(chan, "digits/2-ie");
08529 } else {
08530 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08531 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08532 }
08533 } else {
08534 res = say_and_wait(chan, vms->newmessages, chan->language);
08535 }
08536 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08537 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08538 } else {
08539 res = say_and_wait(chan, vms->newmessages, chan->language);
08540 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08541 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08542 }
08543 if (!res && vms->oldmessages)
08544 res = ast_play_and_wait(chan, "vm-and");
08545 }
08546 if (!res && vms->oldmessages) {
08547 num = div(vms->oldmessages, 10);
08548 if (vms->oldmessages == 1) {
08549 res = ast_play_and_wait(chan, "digits/1-a");
08550 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08551 res = res ? res : ast_play_and_wait(chan, "vm-message");
08552 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08553 if (num.rem == 2) {
08554 if (!num.quot) {
08555 res = ast_play_and_wait(chan, "digits/2-ie");
08556 } else {
08557 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08558 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08559 }
08560 } else {
08561 res = say_and_wait(chan, vms->oldmessages, chan->language);
08562 }
08563 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08564 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08565 } else {
08566 res = say_and_wait(chan, vms->oldmessages, chan->language);
08567 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08568 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08569 }
08570 }
08571
08572 return res;
08573 }
08574
08575
08576 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08577 {
08578
08579 int res;
08580
08581 res = ast_play_and_wait(chan, "vm-youhave");
08582 if (res)
08583 return res;
08584
08585 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08586 res = ast_play_and_wait(chan, "vm-no");
08587 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08588 return res;
08589 }
08590
08591 if (vms->newmessages) {
08592 if ((vms->newmessages == 1)) {
08593 res = ast_play_and_wait(chan, "digits/ett");
08594 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08595 res = res ? res : ast_play_and_wait(chan, "vm-message");
08596 } else {
08597 res = say_and_wait(chan, vms->newmessages, chan->language);
08598 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08599 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08600 }
08601 if (!res && vms->oldmessages)
08602 res = ast_play_and_wait(chan, "vm-and");
08603 }
08604 if (!res && vms->oldmessages) {
08605 if (vms->oldmessages == 1) {
08606 res = ast_play_and_wait(chan, "digits/ett");
08607 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08608 res = res ? res : ast_play_and_wait(chan, "vm-message");
08609 } else {
08610 res = say_and_wait(chan, vms->oldmessages, chan->language);
08611 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08612 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08613 }
08614 }
08615
08616 return res;
08617 }
08618
08619
08620 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08621 {
08622
08623 int res;
08624
08625 res = ast_play_and_wait(chan, "vm-youhave");
08626 if (res)
08627 return res;
08628
08629 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08630 res = ast_play_and_wait(chan, "vm-no");
08631 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08632 return res;
08633 }
08634
08635 if (vms->newmessages) {
08636 if ((vms->newmessages == 1)) {
08637 res = ast_play_and_wait(chan, "digits/1");
08638 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08639 res = res ? res : ast_play_and_wait(chan, "vm-message");
08640 } else {
08641 res = say_and_wait(chan, vms->newmessages, chan->language);
08642 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08643 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08644 }
08645 if (!res && vms->oldmessages)
08646 res = ast_play_and_wait(chan, "vm-and");
08647 }
08648 if (!res && vms->oldmessages) {
08649 if (vms->oldmessages == 1) {
08650 res = ast_play_and_wait(chan, "digits/1");
08651 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08652 res = res ? res : ast_play_and_wait(chan, "vm-message");
08653 } else {
08654 res = say_and_wait(chan, vms->oldmessages, chan->language);
08655 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08656 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08657 }
08658 }
08659
08660 return res;
08661 }
08662
08663
08664 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08665 {
08666
08667 int res;
08668 res = ast_play_and_wait(chan, "vm-youhave");
08669 if (!res) {
08670 if (vms->newmessages) {
08671 if ((vms->newmessages == 1))
08672 res = ast_play_and_wait(chan, "digits/1F");
08673 else
08674 res = say_and_wait(chan, vms->newmessages, chan->language);
08675 if (!res)
08676 res = ast_play_and_wait(chan, "vm-INBOX");
08677 if (vms->oldmessages && !res)
08678 res = ast_play_and_wait(chan, "vm-and");
08679 else if (!res) {
08680 if ((vms->newmessages == 1))
08681 res = ast_play_and_wait(chan, "vm-message");
08682 else
08683 res = ast_play_and_wait(chan, "vm-messages");
08684 }
08685
08686 }
08687 if (!res && vms->oldmessages) {
08688 if (vms->oldmessages == 1)
08689 res = ast_play_and_wait(chan, "digits/1F");
08690 else
08691 res = say_and_wait(chan, vms->oldmessages, chan->language);
08692 if (!res)
08693 res = ast_play_and_wait(chan, "vm-Old");
08694 if (!res) {
08695 if (vms->oldmessages == 1)
08696 res = ast_play_and_wait(chan, "vm-message");
08697 else
08698 res = ast_play_and_wait(chan, "vm-messages");
08699 }
08700 }
08701 if (!res) {
08702 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08703 res = ast_play_and_wait(chan, "vm-no");
08704 if (!res)
08705 res = ast_play_and_wait(chan, "vm-messages");
08706 }
08707 }
08708 }
08709 return res;
08710 }
08711
08712
08713 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08714 {
08715
08716 int res;
08717 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08718 res = ast_play_and_wait(chan, "vm-youhaveno");
08719 if (!res)
08720 res = ast_play_and_wait(chan, "vm-messages");
08721 } else {
08722 res = ast_play_and_wait(chan, "vm-youhave");
08723 }
08724 if (!res) {
08725 if (vms->newmessages) {
08726 if (!res) {
08727 if ((vms->newmessages == 1)) {
08728 res = ast_play_and_wait(chan, "digits/1M");
08729 if (!res)
08730 res = ast_play_and_wait(chan, "vm-message");
08731 if (!res)
08732 res = ast_play_and_wait(chan, "vm-INBOXs");
08733 } else {
08734 res = say_and_wait(chan, vms->newmessages, chan->language);
08735 if (!res)
08736 res = ast_play_and_wait(chan, "vm-messages");
08737 if (!res)
08738 res = ast_play_and_wait(chan, "vm-INBOX");
08739 }
08740 }
08741 if (vms->oldmessages && !res)
08742 res = ast_play_and_wait(chan, "vm-and");
08743 }
08744 if (vms->oldmessages) {
08745 if (!res) {
08746 if (vms->oldmessages == 1) {
08747 res = ast_play_and_wait(chan, "digits/1M");
08748 if (!res)
08749 res = ast_play_and_wait(chan, "vm-message");
08750 if (!res)
08751 res = ast_play_and_wait(chan, "vm-Olds");
08752 } else {
08753 res = say_and_wait(chan, vms->oldmessages, chan->language);
08754 if (!res)
08755 res = ast_play_and_wait(chan, "vm-messages");
08756 if (!res)
08757 res = ast_play_and_wait(chan, "vm-Old");
08758 }
08759 }
08760 }
08761 }
08762 return res;
08763 }
08764
08765
08766 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08767
08768 int res;
08769 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08770 res = ast_play_and_wait(chan, "vm-nomessages");
08771 return res;
08772 } else {
08773 res = ast_play_and_wait(chan, "vm-youhave");
08774 }
08775 if (vms->newmessages) {
08776 if (!res)
08777 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08778 if ((vms->newmessages == 1)) {
08779 if (!res)
08780 res = ast_play_and_wait(chan, "vm-message");
08781 if (!res)
08782 res = ast_play_and_wait(chan, "vm-INBOXs");
08783 } else {
08784 if (!res)
08785 res = ast_play_and_wait(chan, "vm-messages");
08786 if (!res)
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 }
08792 if (vms->oldmessages) {
08793 if (!res)
08794 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08795 if (vms->oldmessages == 1) {
08796 if (!res)
08797 res = ast_play_and_wait(chan, "vm-message");
08798 if (!res)
08799 res = ast_play_and_wait(chan, "vm-Olds");
08800 } else {
08801 if (!res)
08802 res = ast_play_and_wait(chan, "vm-messages");
08803 if (!res)
08804 res = ast_play_and_wait(chan, "vm-Old");
08805 }
08806 }
08807 return res;
08808 }
08809
08810
08811 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08812 {
08813
08814 int res;
08815 res = ast_play_and_wait(chan, "vm-youhave");
08816 if (!res) {
08817 if (vms->newmessages) {
08818 res = say_and_wait(chan, vms->newmessages, chan->language);
08819 if (!res)
08820 res = ast_play_and_wait(chan, "vm-INBOX");
08821 if (vms->oldmessages && !res)
08822 res = ast_play_and_wait(chan, "vm-and");
08823 else if (!res) {
08824 if ((vms->newmessages == 1))
08825 res = ast_play_and_wait(chan, "vm-message");
08826 else
08827 res = ast_play_and_wait(chan, "vm-messages");
08828 }
08829
08830 }
08831 if (!res && vms->oldmessages) {
08832 res = say_and_wait(chan, vms->oldmessages, chan->language);
08833 if (!res)
08834 res = ast_play_and_wait(chan, "vm-Old");
08835 if (!res) {
08836 if (vms->oldmessages == 1)
08837 res = ast_play_and_wait(chan, "vm-message");
08838 else
08839 res = ast_play_and_wait(chan, "vm-messages");
08840 }
08841 }
08842 if (!res) {
08843 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08844 res = ast_play_and_wait(chan, "vm-no");
08845 if (!res)
08846 res = ast_play_and_wait(chan, "vm-messages");
08847 }
08848 }
08849 }
08850 return res;
08851 }
08852
08853
08854 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08855 {
08856
08857 int res;
08858 res = ast_play_and_wait(chan, "vm-youhave");
08859 if (!res) {
08860 if (vms->newmessages) {
08861 res = say_and_wait(chan, vms->newmessages, chan->language);
08862 if (!res) {
08863 if (vms->newmessages == 1)
08864 res = ast_play_and_wait(chan, "vm-INBOXs");
08865 else
08866 res = ast_play_and_wait(chan, "vm-INBOX");
08867 }
08868 if (vms->oldmessages && !res)
08869 res = ast_play_and_wait(chan, "vm-and");
08870 else if (!res) {
08871 if ((vms->newmessages == 1))
08872 res = ast_play_and_wait(chan, "vm-message");
08873 else
08874 res = ast_play_and_wait(chan, "vm-messages");
08875 }
08876
08877 }
08878 if (!res && vms->oldmessages) {
08879 res = say_and_wait(chan, vms->oldmessages, chan->language);
08880 if (!res) {
08881 if (vms->oldmessages == 1)
08882 res = ast_play_and_wait(chan, "vm-Olds");
08883 else
08884 res = ast_play_and_wait(chan, "vm-Old");
08885 }
08886 if (!res) {
08887 if (vms->oldmessages == 1)
08888 res = ast_play_and_wait(chan, "vm-message");
08889 else
08890 res = ast_play_and_wait(chan, "vm-messages");
08891 }
08892 }
08893 if (!res) {
08894 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08895 res = ast_play_and_wait(chan, "vm-no");
08896 if (!res)
08897 res = ast_play_and_wait(chan, "vm-messages");
08898 }
08899 }
08900 }
08901 return res;
08902 }
08903
08904
08905 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08906 {
08907
08908 int res;
08909 res = ast_play_and_wait(chan, "vm-youhave");
08910 if (!res) {
08911 if (vms->newmessages) {
08912 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08913 if (!res) {
08914 if ((vms->newmessages == 1)) {
08915 res = ast_play_and_wait(chan, "vm-message");
08916 if (!res)
08917 res = ast_play_and_wait(chan, "vm-INBOXs");
08918 } else {
08919 res = ast_play_and_wait(chan, "vm-messages");
08920 if (!res)
08921 res = ast_play_and_wait(chan, "vm-INBOX");
08922 }
08923 }
08924 if (vms->oldmessages && !res)
08925 res = ast_play_and_wait(chan, "vm-and");
08926 }
08927 if (!res && vms->oldmessages) {
08928 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08929 if (!res) {
08930 if (vms->oldmessages == 1) {
08931 res = ast_play_and_wait(chan, "vm-message");
08932 if (!res)
08933 res = ast_play_and_wait(chan, "vm-Olds");
08934 } else {
08935 res = ast_play_and_wait(chan, "vm-messages");
08936 if (!res)
08937 res = ast_play_and_wait(chan, "vm-Old");
08938 }
08939 }
08940 }
08941 if (!res) {
08942 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08943 res = ast_play_and_wait(chan, "vm-no");
08944 if (!res)
08945 res = ast_play_and_wait(chan, "vm-messages");
08946 }
08947 }
08948 }
08949 return res;
08950 }
08951
08952
08953
08954
08955
08956
08957
08958
08959
08960
08961
08962
08963
08964
08965
08966
08967
08968 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08969 {
08970 int res;
08971 res = ast_play_and_wait(chan, "vm-youhave");
08972 if (!res) {
08973 if (vms->newmessages) {
08974 if (vms->newmessages == 1) {
08975 res = ast_play_and_wait(chan, "digits/jednu");
08976 } else {
08977 res = say_and_wait(chan, vms->newmessages, chan->language);
08978 }
08979 if (!res) {
08980 if ((vms->newmessages == 1))
08981 res = ast_play_and_wait(chan, "vm-novou");
08982 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08983 res = ast_play_and_wait(chan, "vm-nove");
08984 if (vms->newmessages > 4)
08985 res = ast_play_and_wait(chan, "vm-novych");
08986 }
08987 if (vms->oldmessages && !res)
08988 res = ast_play_and_wait(chan, "vm-and");
08989 else if (!res) {
08990 if ((vms->newmessages == 1))
08991 res = ast_play_and_wait(chan, "vm-zpravu");
08992 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08993 res = ast_play_and_wait(chan, "vm-zpravy");
08994 if (vms->newmessages > 4)
08995 res = ast_play_and_wait(chan, "vm-zprav");
08996 }
08997 }
08998 if (!res && vms->oldmessages) {
08999 res = say_and_wait(chan, vms->oldmessages, chan->language);
09000 if (!res) {
09001 if ((vms->oldmessages == 1))
09002 res = ast_play_and_wait(chan, "vm-starou");
09003 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
09004 res = ast_play_and_wait(chan, "vm-stare");
09005 if (vms->oldmessages > 4)
09006 res = ast_play_and_wait(chan, "vm-starych");
09007 }
09008 if (!res) {
09009 if ((vms->oldmessages == 1))
09010 res = ast_play_and_wait(chan, "vm-zpravu");
09011 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
09012 res = ast_play_and_wait(chan, "vm-zpravy");
09013 if (vms->oldmessages > 4)
09014 res = ast_play_and_wait(chan, "vm-zprav");
09015 }
09016 }
09017 if (!res) {
09018 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09019 res = ast_play_and_wait(chan, "vm-no");
09020 if (!res)
09021 res = ast_play_and_wait(chan, "vm-zpravy");
09022 }
09023 }
09024 }
09025 return res;
09026 }
09027
09028
09029 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
09030 {
09031 int res;
09032
09033 res = ast_play_and_wait(chan, "vm-you");
09034
09035 if (!res && vms->newmessages) {
09036 res = ast_play_and_wait(chan, "vm-have");
09037 if (!res)
09038 res = say_and_wait(chan, vms->newmessages, chan->language);
09039 if (!res)
09040 res = ast_play_and_wait(chan, "vm-tong");
09041 if (!res)
09042 res = ast_play_and_wait(chan, "vm-INBOX");
09043 if (vms->oldmessages && !res)
09044 res = ast_play_and_wait(chan, "vm-and");
09045 else if (!res)
09046 res = ast_play_and_wait(chan, "vm-messages");
09047 }
09048 if (!res && vms->oldmessages) {
09049 res = ast_play_and_wait(chan, "vm-have");
09050 if (!res)
09051 res = say_and_wait(chan, vms->oldmessages, chan->language);
09052 if (!res)
09053 res = ast_play_and_wait(chan, "vm-tong");
09054 if (!res)
09055 res = ast_play_and_wait(chan, "vm-Old");
09056 if (!res)
09057 res = ast_play_and_wait(chan, "vm-messages");
09058 }
09059 if (!res && !vms->oldmessages && !vms->newmessages) {
09060 res = ast_play_and_wait(chan, "vm-haveno");
09061 if (!res)
09062 res = ast_play_and_wait(chan, "vm-messages");
09063 }
09064 return res;
09065 }
09066
09067
09068 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09069 {
09070 int res;
09071
09072
09073 res = ast_play_and_wait(chan, "vm-youhave");
09074 if (!res) {
09075 if (vms->newmessages) {
09076 res = say_and_wait(chan, vms->newmessages, chan->language);
09077 if (!res)
09078 res = ast_play_and_wait(chan, "vm-INBOX");
09079 if (vms->oldmessages && !res)
09080 res = ast_play_and_wait(chan, "vm-and");
09081 }
09082 if (!res && vms->oldmessages) {
09083 res = say_and_wait(chan, vms->oldmessages, chan->language);
09084 if (!res)
09085 res = ast_play_and_wait(chan, "vm-Old");
09086 }
09087 if (!res) {
09088 if (!vms->oldmessages && !vms->newmessages) {
09089 res = ast_play_and_wait(chan, "vm-no");
09090 if (!res)
09091 res = ast_play_and_wait(chan, "vm-message");
09092 }
09093 }
09094 }
09095 return res;
09096 }
09097
09098 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09099 {
09100 char prefile[256];
09101
09102
09103 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09104 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09105 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09106 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09107 ast_play_and_wait(chan, "vm-tempgreetactive");
09108 }
09109 DISPOSE(prefile, -1);
09110 }
09111
09112
09113 if (0) {
09114 return 0;
09115 } else if (!strncasecmp(chan->language, "cs", 2)) {
09116 return vm_intro_cs(chan, vms);
09117 } else if (!strncasecmp(chan->language, "cz", 2)) {
09118 static int deprecation_warning = 0;
09119 if (deprecation_warning++ % 10 == 0) {
09120 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09121 }
09122 return vm_intro_cs(chan, vms);
09123 } else if (!strncasecmp(chan->language, "de", 2)) {
09124 return vm_intro_de(chan, vms);
09125 } else if (!strncasecmp(chan->language, "es", 2)) {
09126 return vm_intro_es(chan, vms);
09127 } else if (!strncasecmp(chan->language, "fr", 2)) {
09128 return vm_intro_fr(chan, vms);
09129 } else if (!strncasecmp(chan->language, "gr", 2)) {
09130 return vm_intro_gr(chan, vms);
09131 } else if (!strncasecmp(chan->language, "he", 2)) {
09132 return vm_intro_he(chan, vms);
09133 } else if (!strncasecmp(chan->language, "it", 2)) {
09134 return vm_intro_it(chan, vms);
09135 } else if (!strncasecmp(chan->language, "nl", 2)) {
09136 return vm_intro_nl(chan, vms);
09137 } else if (!strncasecmp(chan->language, "no", 2)) {
09138 return vm_intro_no(chan, vms);
09139 } else if (!strncasecmp(chan->language, "pl", 2)) {
09140 return vm_intro_pl(chan, vms);
09141 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09142 return vm_intro_pt_BR(chan, vms);
09143 } else if (!strncasecmp(chan->language, "pt", 2)) {
09144 return vm_intro_pt(chan, vms);
09145 } else if (!strncasecmp(chan->language, "ru", 2)) {
09146 return vm_intro_multilang(chan, vms, "n");
09147 } else if (!strncasecmp(chan->language, "se", 2)) {
09148 return vm_intro_se(chan, vms);
09149 } else if (!strncasecmp(chan->language, "ua", 2)) {
09150 return vm_intro_multilang(chan, vms, "n");
09151 } else if (!strncasecmp(chan->language, "vi", 2)) {
09152 return vm_intro_vi(chan, vms);
09153 } else if (!strncasecmp(chan->language, "zh", 2)) {
09154 return vm_intro_zh(chan, vms);
09155 } else {
09156 return vm_intro_en(chan, vms);
09157 }
09158 }
09159
09160 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09161 {
09162 int res = 0;
09163
09164 while (!res) {
09165 if (vms->starting) {
09166 if (vms->lastmsg > -1) {
09167 if (skipadvanced)
09168 res = ast_play_and_wait(chan, "vm-onefor-full");
09169 else
09170 res = ast_play_and_wait(chan, "vm-onefor");
09171 if (!res)
09172 res = vm_play_folder_name(chan, vms->vmbox);
09173 }
09174 if (!res) {
09175 if (skipadvanced)
09176 res = ast_play_and_wait(chan, "vm-opts-full");
09177 else
09178 res = ast_play_and_wait(chan, "vm-opts");
09179 }
09180 } else {
09181
09182 if (skipadvanced) {
09183 res = ast_play_and_wait(chan, "vm-onefor-full");
09184 if (!res)
09185 res = vm_play_folder_name(chan, vms->vmbox);
09186 res = ast_play_and_wait(chan, "vm-opts-full");
09187 }
09188
09189
09190
09191
09192
09193
09194 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09195 res = ast_play_and_wait(chan, "vm-prev");
09196 }
09197 if (!res && !skipadvanced)
09198 res = ast_play_and_wait(chan, "vm-advopts");
09199 if (!res)
09200 res = ast_play_and_wait(chan, "vm-repeat");
09201
09202
09203
09204
09205
09206
09207 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09208 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09209 res = ast_play_and_wait(chan, "vm-next");
09210 }
09211 if (!res) {
09212 int curmsg_deleted;
09213 #ifdef IMAP_STORAGE
09214 ast_mutex_lock(&vms->lock);
09215 #endif
09216 curmsg_deleted = vms->deleted[vms->curmsg];
09217 #ifdef IMAP_STORAGE
09218 ast_mutex_unlock(&vms->lock);
09219 #endif
09220 if (!curmsg_deleted) {
09221 res = ast_play_and_wait(chan, "vm-delete");
09222 } else {
09223 res = ast_play_and_wait(chan, "vm-undelete");
09224 }
09225 if (!res) {
09226 res = ast_play_and_wait(chan, "vm-toforward");
09227 }
09228 if (!res) {
09229 res = ast_play_and_wait(chan, "vm-savemessage");
09230 }
09231 }
09232 }
09233 if (!res) {
09234 res = ast_play_and_wait(chan, "vm-helpexit");
09235 }
09236 if (!res)
09237 res = ast_waitfordigit(chan, 6000);
09238 if (!res) {
09239 vms->repeats++;
09240 if (vms->repeats > 2) {
09241 res = 't';
09242 }
09243 }
09244 }
09245 return res;
09246 }
09247
09248 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09249 {
09250 int res = 0;
09251
09252 while (!res) {
09253 if (vms->lastmsg > -1) {
09254 res = ast_play_and_wait(chan, "vm-listen");
09255 if (!res)
09256 res = vm_play_folder_name(chan, vms->vmbox);
09257 if (!res)
09258 res = ast_play_and_wait(chan, "press");
09259 if (!res)
09260 res = ast_play_and_wait(chan, "digits/1");
09261 }
09262 if (!res)
09263 res = ast_play_and_wait(chan, "vm-opts");
09264 if (!res) {
09265 vms->starting = 0;
09266 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09267 }
09268 }
09269 return res;
09270 }
09271
09272 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09273 {
09274 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09275 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09276 } else {
09277 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09278 }
09279 }
09280
09281
09282 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09283 {
09284 int cmd = 0;
09285 int duration = 0;
09286 int tries = 0;
09287 char newpassword[80] = "";
09288 char newpassword2[80] = "";
09289 char prefile[PATH_MAX] = "";
09290 unsigned char buf[256];
09291 int bytes = 0;
09292
09293 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09294 if (ast_adsi_available(chan)) {
09295 bytes += adsi_logo(buf + bytes);
09296 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09297 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09298 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09299 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09300 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09301 }
09302
09303
09304 if (ast_test_flag(vmu, VM_FORCENAME)) {
09305 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09306 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09307 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09308 if (cmd < 0 || cmd == 't' || cmd == '#')
09309 return cmd;
09310 }
09311 }
09312
09313
09314 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09315 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09316 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09317 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09318 if (cmd < 0 || cmd == 't' || cmd == '#')
09319 return cmd;
09320 }
09321
09322 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09323 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09324 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09325 if (cmd < 0 || cmd == 't' || cmd == '#')
09326 return cmd;
09327 }
09328 }
09329
09330
09331
09332
09333
09334 for (;;) {
09335 newpassword[1] = '\0';
09336 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09337 if (cmd == '#')
09338 newpassword[0] = '\0';
09339 if (cmd < 0 || cmd == 't' || cmd == '#')
09340 return cmd;
09341 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09342 if (cmd < 0 || cmd == 't' || cmd == '#')
09343 return cmd;
09344 cmd = check_password(vmu, newpassword);
09345 if (cmd != 0) {
09346 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09347 cmd = ast_play_and_wait(chan, vm_invalid_password);
09348 } else {
09349 newpassword2[1] = '\0';
09350 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09351 if (cmd == '#')
09352 newpassword2[0] = '\0';
09353 if (cmd < 0 || cmd == 't' || cmd == '#')
09354 return cmd;
09355 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09356 if (cmd < 0 || cmd == 't' || cmd == '#')
09357 return cmd;
09358 if (!strcmp(newpassword, newpassword2))
09359 break;
09360 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09361 cmd = ast_play_and_wait(chan, vm_mismatch);
09362 }
09363 if (++tries == 3)
09364 return -1;
09365 if (cmd != 0) {
09366 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09367 }
09368 }
09369 if (pwdchange & PWDCHANGE_INTERNAL)
09370 vm_change_password(vmu, newpassword);
09371 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09372 vm_change_password_shell(vmu, newpassword);
09373
09374 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09375 cmd = ast_play_and_wait(chan, vm_passchanged);
09376
09377 return cmd;
09378 }
09379
09380 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09381 {
09382 int cmd = 0;
09383 int retries = 0;
09384 int duration = 0;
09385 char newpassword[80] = "";
09386 char newpassword2[80] = "";
09387 char prefile[PATH_MAX] = "";
09388 unsigned char buf[256];
09389 int bytes = 0;
09390
09391 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09392 if (ast_adsi_available(chan)) {
09393 bytes += adsi_logo(buf + bytes);
09394 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09395 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09396 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09397 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09398 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09399 }
09400 while ((cmd >= 0) && (cmd != 't')) {
09401 if (cmd)
09402 retries = 0;
09403 switch (cmd) {
09404 case '1':
09405 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09406 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09407 break;
09408 case '2':
09409 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09410 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09411 break;
09412 case '3':
09413 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09414 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09415 break;
09416 case '4':
09417 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09418 break;
09419 case '5':
09420 if (vmu->password[0] == '-') {
09421 cmd = ast_play_and_wait(chan, "vm-no");
09422 break;
09423 }
09424 newpassword[1] = '\0';
09425 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09426 if (cmd == '#')
09427 newpassword[0] = '\0';
09428 else {
09429 if (cmd < 0)
09430 break;
09431 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09432 break;
09433 }
09434 }
09435 cmd = check_password(vmu, newpassword);
09436 if (cmd != 0) {
09437 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09438 cmd = ast_play_and_wait(chan, vm_invalid_password);
09439 if (!cmd) {
09440 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09441 }
09442 break;
09443 }
09444 newpassword2[1] = '\0';
09445 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09446 if (cmd == '#')
09447 newpassword2[0] = '\0';
09448 else {
09449 if (cmd < 0)
09450 break;
09451
09452 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09453 break;
09454 }
09455 }
09456 if (strcmp(newpassword, newpassword2)) {
09457 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09458 cmd = ast_play_and_wait(chan, vm_mismatch);
09459 if (!cmd) {
09460 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09461 }
09462 break;
09463 }
09464
09465 if (pwdchange & PWDCHANGE_INTERNAL) {
09466 vm_change_password(vmu, newpassword);
09467 }
09468 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09469 vm_change_password_shell(vmu, newpassword);
09470 }
09471
09472 ast_debug(1, "User %s set password to %s of length %d\n",
09473 vms->username, newpassword, (int) strlen(newpassword));
09474 cmd = ast_play_and_wait(chan, vm_passchanged);
09475 break;
09476 case '*':
09477 cmd = 't';
09478 break;
09479 default:
09480 cmd = 0;
09481 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09482 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09483 if (ast_fileexists(prefile, NULL, NULL)) {
09484 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09485 }
09486 DISPOSE(prefile, -1);
09487 if (!cmd) {
09488 cmd = ast_play_and_wait(chan, "vm-options");
09489 }
09490 if (!cmd) {
09491 cmd = ast_waitfordigit(chan, 6000);
09492 }
09493 if (!cmd) {
09494 retries++;
09495 }
09496 if (retries > 3) {
09497 cmd = 't';
09498 }
09499 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09500 }
09501 }
09502 if (cmd == 't')
09503 cmd = 0;
09504 return cmd;
09505 }
09506
09507
09508
09509
09510
09511
09512
09513
09514
09515
09516
09517
09518
09519
09520
09521
09522
09523 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09524 {
09525 int cmd = 0;
09526 int retries = 0;
09527 int duration = 0;
09528 char prefile[PATH_MAX] = "";
09529 unsigned char buf[256];
09530 int bytes = 0;
09531
09532 if (ast_adsi_available(chan)) {
09533 bytes += adsi_logo(buf + bytes);
09534 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09535 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09536 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09537 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09538 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09539 }
09540
09541 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09542 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09543 while ((cmd >= 0) && (cmd != 't')) {
09544 if (cmd)
09545 retries = 0;
09546 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09547 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09548 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09549 if (cmd == -1) {
09550 break;
09551 }
09552 cmd = 't';
09553 } else {
09554 switch (cmd) {
09555 case '1':
09556 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09557 break;
09558 case '2':
09559 DELETE(prefile, -1, prefile, vmu);
09560 ast_play_and_wait(chan, "vm-tempremoved");
09561 cmd = 't';
09562 break;
09563 case '*':
09564 cmd = 't';
09565 break;
09566 default:
09567 cmd = ast_play_and_wait(chan,
09568 ast_fileexists(prefile, NULL, NULL) > 0 ?
09569 "vm-tempgreeting2" : "vm-tempgreeting");
09570 if (!cmd) {
09571 cmd = ast_waitfordigit(chan, 6000);
09572 }
09573 if (!cmd) {
09574 retries++;
09575 }
09576 if (retries > 3) {
09577 cmd = 't';
09578 }
09579 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09580 }
09581 }
09582 DISPOSE(prefile, -1);
09583 }
09584 if (cmd == 't')
09585 cmd = 0;
09586 return cmd;
09587 }
09588
09589
09590
09591
09592
09593
09594
09595
09596
09597 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09598 {
09599 int cmd = 0;
09600
09601 if (vms->lastmsg > -1) {
09602 cmd = play_message(chan, vmu, vms);
09603 } else {
09604 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09605 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09606 if (!cmd) {
09607 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09608 cmd = ast_play_and_wait(chan, vms->fn);
09609 }
09610 if (!cmd)
09611 cmd = ast_play_and_wait(chan, "vm-messages");
09612 } else {
09613 if (!cmd)
09614 cmd = ast_play_and_wait(chan, "vm-messages");
09615 if (!cmd) {
09616 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09617 cmd = ast_play_and_wait(chan, vms->fn);
09618 }
09619 }
09620 }
09621 return cmd;
09622 }
09623
09624
09625 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09626 {
09627 int cmd = 0;
09628
09629 if (vms->lastmsg > -1) {
09630 cmd = play_message(chan, vmu, vms);
09631 } else {
09632 if (!strcasecmp(vms->fn, "INBOX")) {
09633 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09634 } else {
09635 cmd = ast_play_and_wait(chan, "vm-nomessages");
09636 }
09637 }
09638 return cmd;
09639 }
09640
09641
09642
09643
09644
09645
09646
09647
09648
09649 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09650 {
09651 int cmd = 0;
09652
09653 if (vms->lastmsg > -1) {
09654 cmd = play_message(chan, vmu, vms);
09655 } else {
09656 cmd = ast_play_and_wait(chan, "vm-youhave");
09657 if (!cmd)
09658 cmd = ast_play_and_wait(chan, "vm-no");
09659 if (!cmd) {
09660 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09661 cmd = ast_play_and_wait(chan, vms->fn);
09662 }
09663 if (!cmd)
09664 cmd = ast_play_and_wait(chan, "vm-messages");
09665 }
09666 return cmd;
09667 }
09668
09669
09670
09671
09672
09673
09674
09675
09676
09677 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09678 {
09679 int cmd;
09680
09681 if (vms->lastmsg > -1) {
09682 cmd = play_message(chan, vmu, vms);
09683 } else {
09684 cmd = ast_play_and_wait(chan, "vm-no");
09685 if (!cmd)
09686 cmd = ast_play_and_wait(chan, "vm-message");
09687 if (!cmd) {
09688 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09689 cmd = ast_play_and_wait(chan, vms->fn);
09690 }
09691 }
09692 return cmd;
09693 }
09694
09695
09696
09697
09698
09699
09700
09701
09702
09703 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09704 {
09705 int cmd;
09706
09707 if (vms->lastmsg > -1) {
09708 cmd = play_message(chan, vmu, vms);
09709 } else {
09710 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09711 if (!cmd)
09712 cmd = ast_play_and_wait(chan, "vm-messages");
09713 if (!cmd) {
09714 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09715 cmd = ast_play_and_wait(chan, vms->fn);
09716 }
09717 }
09718 return cmd;
09719 }
09720
09721
09722
09723
09724
09725
09726
09727
09728
09729 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09730 {
09731 int cmd;
09732
09733 if (vms->lastmsg > -1) {
09734 cmd = play_message(chan, vmu, vms);
09735 } else {
09736 cmd = ast_play_and_wait(chan, "vm-no");
09737 if (!cmd) {
09738 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09739 cmd = ast_play_and_wait(chan, vms->fn);
09740 }
09741 if (!cmd)
09742 cmd = ast_play_and_wait(chan, "vm-messages");
09743 }
09744 return cmd;
09745 }
09746
09747
09748
09749
09750
09751
09752
09753
09754
09755 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09756 {
09757 int cmd;
09758
09759 if (vms->lastmsg > -1) {
09760 cmd = play_message(chan, vmu, vms);
09761 } else {
09762 cmd = ast_play_and_wait(chan, "vm-you");
09763 if (!cmd)
09764 cmd = ast_play_and_wait(chan, "vm-haveno");
09765 if (!cmd)
09766 cmd = ast_play_and_wait(chan, "vm-messages");
09767 if (!cmd) {
09768 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09769 cmd = ast_play_and_wait(chan, vms->fn);
09770 }
09771 }
09772 return cmd;
09773 }
09774
09775
09776
09777
09778
09779
09780
09781
09782
09783 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09784 {
09785 int cmd = 0;
09786
09787 if (vms->lastmsg > -1) {
09788 cmd = play_message(chan, vmu, vms);
09789 } else {
09790 cmd = ast_play_and_wait(chan, "vm-no");
09791 if (!cmd) {
09792 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09793 cmd = ast_play_and_wait(chan, vms->fn);
09794 }
09795 }
09796 return cmd;
09797 }
09798
09799
09800
09801
09802
09803
09804
09805
09806
09807
09808
09809
09810 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09811 {
09812 if (!strncasecmp(chan->language, "es", 2)) {
09813 return vm_browse_messages_es(chan, vms, vmu);
09814 } else if (!strncasecmp(chan->language, "gr", 2)) {
09815 return vm_browse_messages_gr(chan, vms, vmu);
09816 } else if (!strncasecmp(chan->language, "he", 2)) {
09817 return vm_browse_messages_he(chan, vms, vmu);
09818 } else if (!strncasecmp(chan->language, "it", 2)) {
09819 return vm_browse_messages_it(chan, vms, vmu);
09820 } else if (!strncasecmp(chan->language, "pt", 2)) {
09821 return vm_browse_messages_pt(chan, vms, vmu);
09822 } else if (!strncasecmp(chan->language, "vi", 2)) {
09823 return vm_browse_messages_vi(chan, vms, vmu);
09824 } else if (!strncasecmp(chan->language, "zh", 2)) {
09825 return vm_browse_messages_zh(chan, vms, vmu);
09826 } else {
09827 return vm_browse_messages_en(chan, vms, vmu);
09828 }
09829 }
09830
09831 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09832 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09833 int skipuser, int max_logins, int silent)
09834 {
09835 int useadsi = 0, valid = 0, logretries = 0;
09836 char password[AST_MAX_EXTENSION]="", *passptr;
09837 struct ast_vm_user vmus, *vmu = NULL;
09838
09839
09840 adsi_begin(chan, &useadsi);
09841 if (!skipuser && useadsi)
09842 adsi_login(chan);
09843 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09844 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09845 return -1;
09846 }
09847
09848
09849
09850 while (!valid && (logretries < max_logins)) {
09851
09852 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09853 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09854 return -1;
09855 }
09856 if (ast_strlen_zero(mailbox)) {
09857 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09858 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09859 } else {
09860 ast_verb(3, "Username not entered\n");
09861 return -1;
09862 }
09863 } else if (mailbox[0] == '*') {
09864
09865 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09866 if (ast_exists_extension(chan, chan->context, "a", 1,
09867 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09868 return -1;
09869 }
09870 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09871 mailbox[0] = '\0';
09872 }
09873
09874 if (useadsi)
09875 adsi_password(chan);
09876
09877 if (!ast_strlen_zero(prefix)) {
09878 char fullusername[80] = "";
09879 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09880 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09881 ast_copy_string(mailbox, fullusername, mailbox_size);
09882 }
09883
09884 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09885 vmu = find_user(&vmus, context, mailbox);
09886 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09887
09888 password[0] = '\0';
09889 } else {
09890 if (ast_streamfile(chan, vm_password, chan->language)) {
09891 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09892 return -1;
09893 }
09894 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09895 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09896 return -1;
09897 } else if (password[0] == '*') {
09898
09899 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09900 if (ast_exists_extension(chan, chan->context, "a", 1,
09901 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09902 mailbox[0] = '*';
09903 return -1;
09904 }
09905 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09906 mailbox[0] = '\0';
09907
09908 vmu = NULL;
09909 }
09910 }
09911
09912 if (vmu) {
09913 passptr = vmu->password;
09914 if (passptr[0] == '-') passptr++;
09915 }
09916 if (vmu && !strcmp(passptr, password))
09917 valid++;
09918 else {
09919 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09920 if (!ast_strlen_zero(prefix))
09921 mailbox[0] = '\0';
09922 }
09923 logretries++;
09924 if (!valid) {
09925 if (skipuser || logretries >= max_logins) {
09926 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09927 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09928 return -1;
09929 }
09930 } else {
09931 if (useadsi)
09932 adsi_login(chan);
09933 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09934 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09935 return -1;
09936 }
09937 }
09938 if (ast_waitstream(chan, ""))
09939 return -1;
09940 }
09941 }
09942 if (!valid && (logretries >= max_logins)) {
09943 ast_stopstream(chan);
09944 ast_play_and_wait(chan, "vm-goodbye");
09945 return -1;
09946 }
09947 if (vmu && !skipuser) {
09948 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09949 }
09950 return 0;
09951 }
09952
09953 static int vm_execmain(struct ast_channel *chan, const char *data)
09954 {
09955
09956
09957
09958 int res = -1;
09959 int cmd = 0;
09960 int valid = 0;
09961 char prefixstr[80] ="";
09962 char ext_context[256]="";
09963 int box;
09964 int useadsi = 0;
09965 int skipuser = 0;
09966 struct vm_state vms;
09967 struct ast_vm_user *vmu = NULL, vmus;
09968 char *context = NULL;
09969 int silentexit = 0;
09970 struct ast_flags flags = { 0 };
09971 signed char record_gain = 0;
09972 int play_auto = 0;
09973 int play_folder = 0;
09974 int in_urgent = 0;
09975 #ifdef IMAP_STORAGE
09976 int deleted = 0;
09977 #endif
09978
09979
09980 memset(&vms, 0, sizeof(vms));
09981
09982 vms.lastmsg = -1;
09983
09984 memset(&vmus, 0, sizeof(vmus));
09985
09986 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09987 if (chan->_state != AST_STATE_UP) {
09988 ast_debug(1, "Before ast_answer\n");
09989 ast_answer(chan);
09990 }
09991
09992 if (!ast_strlen_zero(data)) {
09993 char *opts[OPT_ARG_ARRAY_SIZE];
09994 char *parse;
09995 AST_DECLARE_APP_ARGS(args,
09996 AST_APP_ARG(argv0);
09997 AST_APP_ARG(argv1);
09998 );
09999
10000 parse = ast_strdupa(data);
10001
10002 AST_STANDARD_APP_ARGS(args, parse);
10003
10004 if (args.argc == 2) {
10005 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10006 return -1;
10007 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10008 int gain;
10009 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
10010 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10011 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10012 return -1;
10013 } else {
10014 record_gain = (signed char) gain;
10015 }
10016 } else {
10017 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
10018 }
10019 }
10020 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
10021 play_auto = 1;
10022 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
10023
10024 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
10025 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
10026 play_folder = -1;
10027 }
10028 } else {
10029 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
10030 }
10031 } else {
10032 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
10033 }
10034 if (play_folder > 9 || play_folder < 0) {
10035 ast_log(AST_LOG_WARNING,
10036 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
10037 opts[OPT_ARG_PLAYFOLDER]);
10038 play_folder = 0;
10039 }
10040 }
10041 } else {
10042
10043 while (*(args.argv0)) {
10044 if (*(args.argv0) == 's')
10045 ast_set_flag(&flags, OPT_SILENT);
10046 else if (*(args.argv0) == 'p')
10047 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
10048 else
10049 break;
10050 (args.argv0)++;
10051 }
10052
10053 }
10054
10055 valid = ast_test_flag(&flags, OPT_SILENT);
10056
10057 if ((context = strchr(args.argv0, '@')))
10058 *context++ = '\0';
10059
10060 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10061 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10062 else
10063 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10064
10065 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10066 skipuser++;
10067 else
10068 valid = 0;
10069 }
10070
10071 if (!valid)
10072 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10073
10074 ast_debug(1, "After vm_authenticate\n");
10075
10076 if (vms.username[0] == '*') {
10077 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10078
10079
10080 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10081 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10082 res = 0;
10083 goto out;
10084 }
10085 }
10086
10087 if (!res) {
10088 valid = 1;
10089 if (!skipuser)
10090 vmu = &vmus;
10091 } else {
10092 res = 0;
10093 }
10094
10095
10096 adsi_begin(chan, &useadsi);
10097
10098 ast_test_suite_assert(valid);
10099 if (!valid) {
10100 goto out;
10101 }
10102 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10103
10104 #ifdef IMAP_STORAGE
10105 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10106 pthread_setspecific(ts_vmstate.key, &vms);
10107
10108 vms.interactive = 1;
10109 vms.updated = 1;
10110 if (vmu)
10111 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10112 vmstate_insert(&vms);
10113 init_vm_state(&vms);
10114 #endif
10115
10116
10117 if (!ast_strlen_zero(vmu->language))
10118 ast_string_field_set(chan, language, vmu->language);
10119
10120
10121 ast_debug(1, "Before open_mailbox\n");
10122 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10123 if (res < 0)
10124 goto out;
10125 vms.oldmessages = vms.lastmsg + 1;
10126 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10127
10128 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10129 if (res < 0)
10130 goto out;
10131 vms.newmessages = vms.lastmsg + 1;
10132 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10133
10134 in_urgent = 1;
10135 res = open_mailbox(&vms, vmu, 11);
10136 if (res < 0)
10137 goto out;
10138 vms.urgentmessages = vms.lastmsg + 1;
10139 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10140
10141
10142 if (play_auto) {
10143 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10144 if (vms.urgentmessages) {
10145 in_urgent = 1;
10146 res = open_mailbox(&vms, vmu, 11);
10147 } else {
10148 in_urgent = 0;
10149 res = open_mailbox(&vms, vmu, play_folder);
10150 }
10151 if (res < 0)
10152 goto out;
10153
10154
10155 if (vms.lastmsg == -1) {
10156 in_urgent = 0;
10157 cmd = vm_browse_messages(chan, &vms, vmu);
10158 res = 0;
10159 goto out;
10160 }
10161 } else {
10162 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10163
10164 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10165 in_urgent = 0;
10166 play_folder = 1;
10167 if (res < 0)
10168 goto out;
10169 } else if (!vms.urgentmessages && vms.newmessages) {
10170
10171 in_urgent = 0;
10172 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10173 if (res < 0)
10174 goto out;
10175 }
10176 }
10177
10178 if (useadsi)
10179 adsi_status(chan, &vms);
10180 res = 0;
10181
10182
10183 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10184 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10185 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10186 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10187 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10188 if ((cmd == 't') || (cmd == '#')) {
10189
10190 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10191 res = 0;
10192 goto out;
10193 } else if (cmd < 0) {
10194
10195 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10196 res = -1;
10197 goto out;
10198 }
10199 }
10200 #ifdef IMAP_STORAGE
10201 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10202 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10203 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10204 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10205 }
10206 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10207 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10208 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10209 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10210 }
10211 #endif
10212
10213 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10214 if (play_auto) {
10215 cmd = '1';
10216 } else {
10217 cmd = vm_intro(chan, vmu, &vms);
10218 }
10219 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10220
10221 vms.repeats = 0;
10222 vms.starting = 1;
10223 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10224
10225 switch (cmd) {
10226 case '1':
10227 vms.curmsg = 0;
10228
10229 case '5':
10230 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10231 cmd = vm_browse_messages(chan, &vms, vmu);
10232 break;
10233 case '2':
10234 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10235 if (useadsi)
10236 adsi_folders(chan, 0, "Change to folder...");
10237
10238 cmd = get_folder2(chan, "vm-changeto", 0);
10239 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10240 if (cmd == '#') {
10241 cmd = 0;
10242 } else if (cmd > 0) {
10243 cmd = cmd - '0';
10244 res = close_mailbox(&vms, vmu);
10245 if (res == ERROR_LOCK_PATH)
10246 goto out;
10247
10248 if (cmd != 11) in_urgent = 0;
10249 res = open_mailbox(&vms, vmu, cmd);
10250 if (res < 0)
10251 goto out;
10252 play_folder = cmd;
10253 cmd = 0;
10254 }
10255 if (useadsi)
10256 adsi_status2(chan, &vms);
10257
10258 if (!cmd) {
10259 cmd = vm_play_folder_name(chan, vms.vmbox);
10260 }
10261
10262 vms.starting = 1;
10263 vms.curmsg = 0;
10264 break;
10265 case '3':
10266 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10267 cmd = 0;
10268 vms.repeats = 0;
10269 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10270 switch (cmd) {
10271 case '1':
10272 if (vms.lastmsg > -1 && !vms.starting) {
10273 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10274 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10275 res = cmd;
10276 goto out;
10277 }
10278 } else {
10279 cmd = ast_play_and_wait(chan, "vm-sorry");
10280 }
10281 cmd = 't';
10282 break;
10283 case '2':
10284 if (!vms.starting)
10285 ast_verb(3, "Callback Requested\n");
10286 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10287 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10288 if (cmd == 9) {
10289 silentexit = 1;
10290 goto out;
10291 } else if (cmd == ERROR_LOCK_PATH) {
10292 res = cmd;
10293 goto out;
10294 }
10295 } else {
10296 cmd = ast_play_and_wait(chan, "vm-sorry");
10297 }
10298 cmd = 't';
10299 break;
10300 case '3':
10301 if (vms.lastmsg > -1 && !vms.starting) {
10302 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10303 if (cmd == ERROR_LOCK_PATH) {
10304 res = cmd;
10305 goto out;
10306 }
10307 } else {
10308 cmd = ast_play_and_wait(chan, "vm-sorry");
10309 }
10310 cmd = 't';
10311 break;
10312 case '4':
10313 if (!ast_strlen_zero(vmu->dialout)) {
10314 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10315 if (cmd == 9) {
10316 silentexit = 1;
10317 goto out;
10318 }
10319 } else {
10320 cmd = ast_play_and_wait(chan, "vm-sorry");
10321 }
10322 cmd = 't';
10323 break;
10324
10325 case '5':
10326 if (ast_test_flag(vmu, VM_SVMAIL)) {
10327 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10328 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10329 res = cmd;
10330 goto out;
10331 }
10332 } else {
10333 cmd = ast_play_and_wait(chan, "vm-sorry");
10334 }
10335 cmd = 't';
10336 break;
10337
10338 case '*':
10339 cmd = 't';
10340 break;
10341
10342 default:
10343 cmd = 0;
10344 if (!vms.starting) {
10345 cmd = ast_play_and_wait(chan, "vm-toreply");
10346 }
10347 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10348 cmd = ast_play_and_wait(chan, "vm-tocallback");
10349 }
10350 if (!cmd && !vms.starting) {
10351 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10352 }
10353 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10354 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10355 }
10356 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10357 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10358 }
10359 if (!cmd) {
10360 cmd = ast_play_and_wait(chan, "vm-starmain");
10361 }
10362 if (!cmd) {
10363 cmd = ast_waitfordigit(chan, 6000);
10364 }
10365 if (!cmd) {
10366 vms.repeats++;
10367 }
10368 if (vms.repeats > 3) {
10369 cmd = 't';
10370 }
10371 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10372 }
10373 }
10374 if (cmd == 't') {
10375 cmd = 0;
10376 vms.repeats = 0;
10377 }
10378 break;
10379 case '4':
10380 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10381 if (vms.curmsg > 0) {
10382 vms.curmsg--;
10383 cmd = play_message(chan, vmu, &vms);
10384 } else {
10385
10386
10387
10388
10389 if (in_urgent == 0 && vms.urgentmessages > 0) {
10390
10391 in_urgent = 1;
10392 res = close_mailbox(&vms, vmu);
10393 if (res == ERROR_LOCK_PATH)
10394 goto out;
10395 res = open_mailbox(&vms, vmu, 11);
10396 if (res < 0)
10397 goto out;
10398 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10399 vms.curmsg = vms.lastmsg;
10400 if (vms.lastmsg < 0) {
10401 cmd = ast_play_and_wait(chan, "vm-nomore");
10402 }
10403 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10404 vms.curmsg = vms.lastmsg;
10405 cmd = play_message(chan, vmu, &vms);
10406 } else {
10407 cmd = ast_play_and_wait(chan, "vm-nomore");
10408 }
10409 }
10410 break;
10411 case '6':
10412 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10413 if (vms.curmsg < vms.lastmsg) {
10414 vms.curmsg++;
10415 cmd = play_message(chan, vmu, &vms);
10416 } else {
10417 if (in_urgent && vms.newmessages > 0) {
10418
10419
10420
10421
10422 in_urgent = 0;
10423 res = close_mailbox(&vms, vmu);
10424 if (res == ERROR_LOCK_PATH)
10425 goto out;
10426 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10427 if (res < 0)
10428 goto out;
10429 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10430 vms.curmsg = -1;
10431 if (vms.lastmsg < 0) {
10432 cmd = ast_play_and_wait(chan, "vm-nomore");
10433 }
10434 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10435 vms.curmsg = 0;
10436 cmd = play_message(chan, vmu, &vms);
10437 } else {
10438 cmd = ast_play_and_wait(chan, "vm-nomore");
10439 }
10440 }
10441 break;
10442 case '7':
10443 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10444 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10445 if (useadsi)
10446 adsi_delete(chan, &vms);
10447 if (vms.deleted[vms.curmsg]) {
10448 if (play_folder == 0) {
10449 if (in_urgent) {
10450 vms.urgentmessages--;
10451 } else {
10452 vms.newmessages--;
10453 }
10454 }
10455 else if (play_folder == 1)
10456 vms.oldmessages--;
10457 cmd = ast_play_and_wait(chan, "vm-deleted");
10458 } else {
10459 if (play_folder == 0) {
10460 if (in_urgent) {
10461 vms.urgentmessages++;
10462 } else {
10463 vms.newmessages++;
10464 }
10465 }
10466 else if (play_folder == 1)
10467 vms.oldmessages++;
10468 cmd = ast_play_and_wait(chan, "vm-undeleted");
10469 }
10470 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10471 if (vms.curmsg < vms.lastmsg) {
10472 vms.curmsg++;
10473 cmd = play_message(chan, vmu, &vms);
10474 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10475 vms.curmsg = 0;
10476 cmd = play_message(chan, vmu, &vms);
10477 } else {
10478
10479
10480
10481
10482 if (in_urgent == 1) {
10483
10484 in_urgent = 0;
10485 res = close_mailbox(&vms, vmu);
10486 if (res == ERROR_LOCK_PATH)
10487 goto out;
10488 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10489 if (res < 0)
10490 goto out;
10491 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10492 vms.curmsg = -1;
10493 if (vms.lastmsg < 0) {
10494 cmd = ast_play_and_wait(chan, "vm-nomore");
10495 }
10496 } else {
10497 cmd = ast_play_and_wait(chan, "vm-nomore");
10498 }
10499 }
10500 }
10501 } else
10502 cmd = 0;
10503 #ifdef IMAP_STORAGE
10504 deleted = 1;
10505 #endif
10506 break;
10507
10508 case '8':
10509 if (vms.lastmsg > -1) {
10510 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10511 if (cmd == ERROR_LOCK_PATH) {
10512 res = cmd;
10513 goto out;
10514 }
10515 } else {
10516
10517
10518
10519
10520 if (in_urgent == 1 && vms.newmessages > 0) {
10521
10522 in_urgent = 0;
10523 res = close_mailbox(&vms, vmu);
10524 if (res == ERROR_LOCK_PATH)
10525 goto out;
10526 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10527 if (res < 0)
10528 goto out;
10529 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10530 vms.curmsg = -1;
10531 if (vms.lastmsg < 0) {
10532 cmd = ast_play_and_wait(chan, "vm-nomore");
10533 }
10534 } else {
10535 cmd = ast_play_and_wait(chan, "vm-nomore");
10536 }
10537 }
10538 break;
10539 case '9':
10540 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10541 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10542
10543 cmd = 0;
10544 break;
10545 }
10546 if (useadsi)
10547 adsi_folders(chan, 1, "Save to folder...");
10548 cmd = get_folder2(chan, "vm-savefolder", 1);
10549 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10550 box = 0;
10551 if (cmd == '#') {
10552 cmd = 0;
10553 break;
10554 } else if (cmd > 0) {
10555 box = cmd = cmd - '0';
10556 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10557 if (cmd == ERROR_LOCK_PATH) {
10558 res = cmd;
10559 goto out;
10560 #ifndef IMAP_STORAGE
10561 } else if (!cmd) {
10562 vms.deleted[vms.curmsg] = 1;
10563 #endif
10564 } else {
10565 vms.deleted[vms.curmsg] = 0;
10566 vms.heard[vms.curmsg] = 0;
10567 }
10568 }
10569 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10570 if (useadsi)
10571 adsi_message(chan, &vms);
10572 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10573 if (!cmd) {
10574 cmd = ast_play_and_wait(chan, "vm-message");
10575 if (!cmd)
10576 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10577 if (!cmd)
10578 cmd = ast_play_and_wait(chan, "vm-savedto");
10579 if (!cmd)
10580 cmd = vm_play_folder_name(chan, vms.fn);
10581 } else {
10582 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10583 }
10584 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10585 if (vms.curmsg < vms.lastmsg) {
10586 vms.curmsg++;
10587 cmd = play_message(chan, vmu, &vms);
10588 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10589 vms.curmsg = 0;
10590 cmd = play_message(chan, vmu, &vms);
10591 } else {
10592
10593
10594
10595
10596 if (in_urgent == 1 && vms.newmessages > 0) {
10597
10598 in_urgent = 0;
10599 res = close_mailbox(&vms, vmu);
10600 if (res == ERROR_LOCK_PATH)
10601 goto out;
10602 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10603 if (res < 0)
10604 goto out;
10605 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10606 vms.curmsg = -1;
10607 if (vms.lastmsg < 0) {
10608 cmd = ast_play_and_wait(chan, "vm-nomore");
10609 }
10610 } else {
10611 cmd = ast_play_and_wait(chan, "vm-nomore");
10612 }
10613 }
10614 }
10615 break;
10616 case '*':
10617 if (!vms.starting) {
10618 cmd = ast_play_and_wait(chan, "vm-onefor");
10619 if (!strncasecmp(chan->language, "he", 2)) {
10620 cmd = ast_play_and_wait(chan, "vm-for");
10621 }
10622 if (!cmd)
10623 cmd = vm_play_folder_name(chan, vms.vmbox);
10624 if (!cmd)
10625 cmd = ast_play_and_wait(chan, "vm-opts");
10626 if (!cmd)
10627 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10628 } else
10629 cmd = 0;
10630 break;
10631 case '0':
10632 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10633 if (useadsi)
10634 adsi_status(chan, &vms);
10635 break;
10636 default:
10637 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10638 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10639 break;
10640 }
10641 }
10642 if ((cmd == 't') || (cmd == '#')) {
10643
10644 res = 0;
10645 } else {
10646
10647 res = -1;
10648 }
10649
10650 out:
10651 if (res > -1) {
10652 ast_stopstream(chan);
10653 adsi_goodbye(chan);
10654 if (valid && res != OPERATOR_EXIT) {
10655 if (silentexit)
10656 res = ast_play_and_wait(chan, "vm-dialout");
10657 else
10658 res = ast_play_and_wait(chan, "vm-goodbye");
10659 }
10660 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10661 res = 0;
10662 }
10663 if (useadsi)
10664 ast_adsi_unload_session(chan);
10665 }
10666 if (vmu)
10667 close_mailbox(&vms, vmu);
10668 if (valid) {
10669 int new = 0, old = 0, urgent = 0;
10670 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10671 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10672
10673 run_externnotify(vmu->context, vmu->mailbox, NULL);
10674 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10675 queue_mwi_event(ext_context, urgent, new, old);
10676 }
10677 #ifdef IMAP_STORAGE
10678
10679 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10680 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10681 ast_mutex_lock(&vms.lock);
10682 #ifdef HAVE_IMAP_TK2006
10683 if (LEVELUIDPLUS (vms.mailstream)) {
10684 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10685 } else
10686 #endif
10687 mail_expunge(vms.mailstream);
10688 ast_mutex_unlock(&vms.lock);
10689 }
10690
10691
10692 if (vmu) {
10693 vmstate_delete(&vms);
10694 }
10695 #endif
10696 if (vmu)
10697 free_user(vmu);
10698
10699 #ifdef IMAP_STORAGE
10700 pthread_setspecific(ts_vmstate.key, NULL);
10701 #endif
10702 return res;
10703 }
10704
10705 static int vm_exec(struct ast_channel *chan, const char *data)
10706 {
10707 int res = 0;
10708 char *tmp;
10709 struct leave_vm_options leave_options;
10710 struct ast_flags flags = { 0 };
10711 char *opts[OPT_ARG_ARRAY_SIZE];
10712 AST_DECLARE_APP_ARGS(args,
10713 AST_APP_ARG(argv0);
10714 AST_APP_ARG(argv1);
10715 );
10716
10717 memset(&leave_options, 0, sizeof(leave_options));
10718
10719 if (chan->_state != AST_STATE_UP)
10720 ast_answer(chan);
10721
10722 if (!ast_strlen_zero(data)) {
10723 tmp = ast_strdupa(data);
10724 AST_STANDARD_APP_ARGS(args, tmp);
10725 if (args.argc == 2) {
10726 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10727 return -1;
10728 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10729 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10730 int gain;
10731
10732 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10733 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10734 return -1;
10735 } else {
10736 leave_options.record_gain = (signed char) gain;
10737 }
10738 }
10739 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10740 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10741 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10742 }
10743 }
10744 } else {
10745 char temp[256];
10746 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10747 if (res < 0)
10748 return res;
10749 if (ast_strlen_zero(temp))
10750 return 0;
10751 args.argv0 = ast_strdupa(temp);
10752 }
10753
10754 res = leave_voicemail(chan, args.argv0, &leave_options);
10755 if (res == 't') {
10756 ast_play_and_wait(chan, "vm-goodbye");
10757 res = 0;
10758 }
10759
10760 if (res == OPERATOR_EXIT) {
10761 res = 0;
10762 }
10763
10764 if (res == ERROR_LOCK_PATH) {
10765 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10766 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10767 res = 0;
10768 }
10769
10770 return res;
10771 }
10772
10773 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10774 {
10775 struct ast_vm_user *vmu;
10776
10777 if (!ast_strlen_zero(box) && box[0] == '*') {
10778 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10779 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10780 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10781 "\n\tand will be ignored.\n", box, context);
10782 return NULL;
10783 }
10784
10785 AST_LIST_TRAVERSE(&users, vmu, list) {
10786 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10787 if (strcasecmp(vmu->context, context)) {
10788 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10789 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10790 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10791 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10792 }
10793 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10794 return NULL;
10795 }
10796 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10797 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10798 return NULL;
10799 }
10800 }
10801
10802 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10803 return NULL;
10804
10805 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10806 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10807
10808 AST_LIST_INSERT_TAIL(&users, vmu, list);
10809
10810 return vmu;
10811 }
10812
10813 static int append_mailbox(const char *context, const char *box, const char *data)
10814 {
10815
10816 char *tmp;
10817 char *stringp;
10818 char *s;
10819 struct ast_vm_user *vmu;
10820 char *mailbox_full;
10821 int new = 0, old = 0, urgent = 0;
10822 char secretfn[PATH_MAX] = "";
10823
10824 tmp = ast_strdupa(data);
10825
10826 if (!(vmu = find_or_create(context, box)))
10827 return -1;
10828
10829 populate_defaults(vmu);
10830
10831 stringp = tmp;
10832 if ((s = strsep(&stringp, ","))) {
10833 if (!ast_strlen_zero(s) && s[0] == '*') {
10834 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10835 "\n\tmust be reset in voicemail.conf.\n", box);
10836 }
10837
10838 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10839 }
10840 if (stringp && (s = strsep(&stringp, ","))) {
10841 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10842 }
10843 if (stringp && (s = strsep(&stringp, ","))) {
10844 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10845 }
10846 if (stringp && (s = strsep(&stringp, ","))) {
10847 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10848 }
10849 if (stringp && (s = strsep(&stringp, ","))) {
10850 apply_options(vmu, s);
10851 }
10852
10853 switch (vmu->passwordlocation) {
10854 case OPT_PWLOC_SPOOLDIR:
10855 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10856 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10857 }
10858
10859 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
10860 strcpy(mailbox_full, box);
10861 strcat(mailbox_full, "@");
10862 strcat(mailbox_full, context);
10863
10864 inboxcount2(mailbox_full, &urgent, &new, &old);
10865 queue_mwi_event(mailbox_full, urgent, new, old);
10866
10867 return 0;
10868 }
10869
10870 AST_TEST_DEFINE(test_voicemail_vmuser)
10871 {
10872 int res = 0;
10873 struct ast_vm_user *vmu;
10874
10875 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10876 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10877 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10878 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10879 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10880 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10881 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10882 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10883 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10884 #ifdef IMAP_STORAGE
10885 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10886 "imapfolder=INBOX|imapvmshareid=6000";
10887 #endif
10888
10889 switch (cmd) {
10890 case TEST_INIT:
10891 info->name = "vmuser";
10892 info->category = "/apps/app_voicemail/";
10893 info->summary = "Vmuser unit test";
10894 info->description =
10895 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10896 return AST_TEST_NOT_RUN;
10897 case TEST_EXECUTE:
10898 break;
10899 }
10900
10901 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10902 return AST_TEST_NOT_RUN;
10903 }
10904 populate_defaults(vmu);
10905 ast_set_flag(vmu, VM_ALLOCED);
10906
10907 apply_options(vmu, options_string);
10908
10909 if (!ast_test_flag(vmu, VM_ATTACH)) {
10910 ast_test_status_update(test, "Parse failure for attach option\n");
10911 res = 1;
10912 }
10913 if (strcasecmp(vmu->attachfmt, "wav49")) {
10914 ast_test_status_update(test, "Parse failure for attachftm option\n");
10915 res = 1;
10916 }
10917 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10918 ast_test_status_update(test, "Parse failure for serveremail option\n");
10919 res = 1;
10920 }
10921 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10922 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10923 res = 1;
10924 }
10925 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10926 ast_test_status_update(test, "Parse failure for emailbody option\n");
10927 res = 1;
10928 }
10929 if (strcasecmp(vmu->zonetag, "central")) {
10930 ast_test_status_update(test, "Parse failure for tz option\n");
10931 res = 1;
10932 }
10933 if (!ast_test_flag(vmu, VM_DELETE)) {
10934 ast_test_status_update(test, "Parse failure for delete option\n");
10935 res = 1;
10936 }
10937 if (!ast_test_flag(vmu, VM_SAYCID)) {
10938 ast_test_status_update(test, "Parse failure for saycid option\n");
10939 res = 1;
10940 }
10941 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10942 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10943 res = 1;
10944 }
10945 if (!ast_test_flag(vmu, VM_REVIEW)) {
10946 ast_test_status_update(test, "Parse failure for review option\n");
10947 res = 1;
10948 }
10949 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10950 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10951 res = 1;
10952 }
10953 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10954 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10955 res = 1;
10956 }
10957 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10958 ast_test_status_update(test, "Parse failure for operator option\n");
10959 res = 1;
10960 }
10961 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10962 ast_test_status_update(test, "Parse failure for envelope option\n");
10963 res = 1;
10964 }
10965 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10966 ast_test_status_update(test, "Parse failure for moveheard option\n");
10967 res = 1;
10968 }
10969 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10970 ast_test_status_update(test, "Parse failure for sayduration option\n");
10971 res = 1;
10972 }
10973 if (vmu->saydurationm != 5) {
10974 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10975 res = 1;
10976 }
10977 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10978 ast_test_status_update(test, "Parse failure for forcename option\n");
10979 res = 1;
10980 }
10981 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10982 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10983 res = 1;
10984 }
10985 if (strcasecmp(vmu->callback, "somecontext")) {
10986 ast_test_status_update(test, "Parse failure for callbacks option\n");
10987 res = 1;
10988 }
10989 if (strcasecmp(vmu->dialout, "somecontext2")) {
10990 ast_test_status_update(test, "Parse failure for dialout option\n");
10991 res = 1;
10992 }
10993 if (strcasecmp(vmu->exit, "somecontext3")) {
10994 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10995 res = 1;
10996 }
10997 if (vmu->minsecs != 10) {
10998 ast_test_status_update(test, "Parse failure for minsecs option\n");
10999 res = 1;
11000 }
11001 if (vmu->maxsecs != 100) {
11002 ast_test_status_update(test, "Parse failure for maxsecs option\n");
11003 res = 1;
11004 }
11005 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
11006 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
11007 res = 1;
11008 }
11009 if (vmu->maxdeletedmsg != 50) {
11010 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
11011 res = 1;
11012 }
11013 if (vmu->volgain != 1.3) {
11014 ast_test_status_update(test, "Parse failure for volgain option\n");
11015 res = 1;
11016 }
11017 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
11018 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
11019 res = 1;
11020 }
11021 #ifdef IMAP_STORAGE
11022 apply_options(vmu, option_string2);
11023
11024 if (strcasecmp(vmu->imapuser, "imapuser")) {
11025 ast_test_status_update(test, "Parse failure for imapuser option\n");
11026 res = 1;
11027 }
11028 if (strcasecmp(vmu->imappassword, "imappasswd")) {
11029 ast_test_status_update(test, "Parse failure for imappasswd option\n");
11030 res = 1;
11031 }
11032 if (strcasecmp(vmu->imapfolder, "INBOX")) {
11033 ast_test_status_update(test, "Parse failure for imapfolder option\n");
11034 res = 1;
11035 }
11036 if (strcasecmp(vmu->imapvmshareid, "6000")) {
11037 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
11038 res = 1;
11039 }
11040 #endif
11041
11042 free_user(vmu);
11043 return res ? AST_TEST_FAIL : AST_TEST_PASS;
11044 }
11045
11046 static int vm_box_exists(struct ast_channel *chan, const char *data)
11047 {
11048 struct ast_vm_user svm;
11049 char *context, *box;
11050 AST_DECLARE_APP_ARGS(args,
11051 AST_APP_ARG(mbox);
11052 AST_APP_ARG(options);
11053 );
11054 static int dep_warning = 0;
11055
11056 if (ast_strlen_zero(data)) {
11057 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
11058 return -1;
11059 }
11060
11061 if (!dep_warning) {
11062 dep_warning = 1;
11063 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
11064 }
11065
11066 box = ast_strdupa(data);
11067
11068 AST_STANDARD_APP_ARGS(args, box);
11069
11070 if (args.options) {
11071 }
11072
11073 if ((context = strchr(args.mbox, '@'))) {
11074 *context = '\0';
11075 context++;
11076 }
11077
11078 if (find_user(&svm, context, args.mbox)) {
11079 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11080 } else
11081 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11082
11083 return 0;
11084 }
11085
11086 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11087 {
11088 struct ast_vm_user svm;
11089 AST_DECLARE_APP_ARGS(arg,
11090 AST_APP_ARG(mbox);
11091 AST_APP_ARG(context);
11092 );
11093
11094 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11095
11096 if (ast_strlen_zero(arg.mbox)) {
11097 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11098 return -1;
11099 }
11100
11101 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11102 return 0;
11103 }
11104
11105 static struct ast_custom_function mailbox_exists_acf = {
11106 .name = "MAILBOX_EXISTS",
11107 .read = acf_mailbox_exists,
11108 };
11109
11110 static int vmauthenticate(struct ast_channel *chan, const char *data)
11111 {
11112 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11113 struct ast_vm_user vmus;
11114 char *options = NULL;
11115 int silent = 0, skipuser = 0;
11116 int res = -1;
11117
11118 if (data) {
11119 s = ast_strdupa(data);
11120 user = strsep(&s, ",");
11121 options = strsep(&s, ",");
11122 if (user) {
11123 s = user;
11124 user = strsep(&s, "@");
11125 context = strsep(&s, "");
11126 if (!ast_strlen_zero(user))
11127 skipuser++;
11128 ast_copy_string(mailbox, user, sizeof(mailbox));
11129 }
11130 }
11131
11132 if (options) {
11133 silent = (strchr(options, 's')) != NULL;
11134 }
11135
11136 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11137 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11138 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11139 ast_play_and_wait(chan, "auth-thankyou");
11140 res = 0;
11141 } else if (mailbox[0] == '*') {
11142
11143 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11144 res = 0;
11145 }
11146 }
11147
11148 return res;
11149 }
11150
11151 static char *show_users_realtime(int fd, const char *context)
11152 {
11153 struct ast_config *cfg;
11154 const char *cat = NULL;
11155
11156 if (!(cfg = ast_load_realtime_multientry("voicemail",
11157 "context", context, SENTINEL))) {
11158 return CLI_FAILURE;
11159 }
11160
11161 ast_cli(fd,
11162 "\n"
11163 "=============================================================\n"
11164 "=== Configured Voicemail Users ==============================\n"
11165 "=============================================================\n"
11166 "===\n");
11167
11168 while ((cat = ast_category_browse(cfg, cat))) {
11169 struct ast_variable *var = NULL;
11170 ast_cli(fd,
11171 "=== Mailbox ...\n"
11172 "===\n");
11173 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11174 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11175 ast_cli(fd,
11176 "===\n"
11177 "=== ---------------------------------------------------------\n"
11178 "===\n");
11179 }
11180
11181 ast_cli(fd,
11182 "=============================================================\n"
11183 "\n");
11184
11185 ast_config_destroy(cfg);
11186
11187 return CLI_SUCCESS;
11188 }
11189
11190 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11191 {
11192 int which = 0;
11193 int wordlen;
11194 struct ast_vm_user *vmu;
11195 const char *context = "";
11196
11197
11198 if (pos > 4)
11199 return NULL;
11200 if (pos == 3)
11201 return (state == 0) ? ast_strdup("for") : NULL;
11202 wordlen = strlen(word);
11203 AST_LIST_TRAVERSE(&users, vmu, list) {
11204 if (!strncasecmp(word, vmu->context, wordlen)) {
11205 if (context && strcmp(context, vmu->context) && ++which > state)
11206 return ast_strdup(vmu->context);
11207
11208 context = vmu->context;
11209 }
11210 }
11211 return NULL;
11212 }
11213
11214
11215 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11216 {
11217 struct ast_vm_user *vmu;
11218 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11219 const char *context = NULL;
11220 int users_counter = 0;
11221
11222 switch (cmd) {
11223 case CLI_INIT:
11224 e->command = "voicemail show users";
11225 e->usage =
11226 "Usage: voicemail show users [for <context>]\n"
11227 " Lists all mailboxes currently set up\n";
11228 return NULL;
11229 case CLI_GENERATE:
11230 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11231 }
11232
11233 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11234 return CLI_SHOWUSAGE;
11235 if (a->argc == 5) {
11236 if (strcmp(a->argv[3],"for"))
11237 return CLI_SHOWUSAGE;
11238 context = a->argv[4];
11239 }
11240
11241 if (ast_check_realtime("voicemail")) {
11242 if (!context) {
11243 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11244 return CLI_SHOWUSAGE;
11245 }
11246 return show_users_realtime(a->fd, context);
11247 }
11248
11249 AST_LIST_LOCK(&users);
11250 if (AST_LIST_EMPTY(&users)) {
11251 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11252 AST_LIST_UNLOCK(&users);
11253 return CLI_FAILURE;
11254 }
11255 if (!context) {
11256 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11257 } else {
11258 int count = 0;
11259 AST_LIST_TRAVERSE(&users, vmu, list) {
11260 if (!strcmp(context, vmu->context)) {
11261 count++;
11262 break;
11263 }
11264 }
11265 if (count) {
11266 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11267 } else {
11268 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11269 AST_LIST_UNLOCK(&users);
11270 return CLI_FAILURE;
11271 }
11272 }
11273 AST_LIST_TRAVERSE(&users, vmu, list) {
11274 int newmsgs = 0, oldmsgs = 0;
11275 char count[12], tmp[256] = "";
11276
11277 if (!context || !strcmp(context, vmu->context)) {
11278 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11279 inboxcount(tmp, &newmsgs, &oldmsgs);
11280 snprintf(count, sizeof(count), "%d", newmsgs);
11281 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11282 users_counter++;
11283 }
11284 }
11285 AST_LIST_UNLOCK(&users);
11286 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11287 return CLI_SUCCESS;
11288 }
11289
11290
11291 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11292 {
11293 struct vm_zone *zone;
11294 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11295 char *res = CLI_SUCCESS;
11296
11297 switch (cmd) {
11298 case CLI_INIT:
11299 e->command = "voicemail show zones";
11300 e->usage =
11301 "Usage: voicemail show zones\n"
11302 " Lists zone message formats\n";
11303 return NULL;
11304 case CLI_GENERATE:
11305 return NULL;
11306 }
11307
11308 if (a->argc != 3)
11309 return CLI_SHOWUSAGE;
11310
11311 AST_LIST_LOCK(&zones);
11312 if (!AST_LIST_EMPTY(&zones)) {
11313 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11314 AST_LIST_TRAVERSE(&zones, zone, list) {
11315 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11316 }
11317 } else {
11318 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11319 res = CLI_FAILURE;
11320 }
11321 AST_LIST_UNLOCK(&zones);
11322
11323 return res;
11324 }
11325
11326
11327 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11328 {
11329 switch (cmd) {
11330 case CLI_INIT:
11331 e->command = "voicemail reload";
11332 e->usage =
11333 "Usage: voicemail reload\n"
11334 " Reload voicemail configuration\n";
11335 return NULL;
11336 case CLI_GENERATE:
11337 return NULL;
11338 }
11339
11340 if (a->argc != 2)
11341 return CLI_SHOWUSAGE;
11342
11343 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11344 load_config(1);
11345
11346 return CLI_SUCCESS;
11347 }
11348
11349 static struct ast_cli_entry cli_voicemail[] = {
11350 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11351 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11352 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11353 };
11354
11355 #ifdef IMAP_STORAGE
11356 #define DATA_EXPORT_VM_USERS(USER) \
11357 USER(ast_vm_user, context, AST_DATA_STRING) \
11358 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11359 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11360 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11361 USER(ast_vm_user, email, AST_DATA_STRING) \
11362 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11363 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11364 USER(ast_vm_user, pager, AST_DATA_STRING) \
11365 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11366 USER(ast_vm_user, language, AST_DATA_STRING) \
11367 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11368 USER(ast_vm_user, callback, AST_DATA_STRING) \
11369 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11370 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11371 USER(ast_vm_user, exit, AST_DATA_STRING) \
11372 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11373 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11374 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11375 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11376 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11377 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11378 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11379 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11380 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11381 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11382 #else
11383 #define DATA_EXPORT_VM_USERS(USER) \
11384 USER(ast_vm_user, context, AST_DATA_STRING) \
11385 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11386 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11387 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11388 USER(ast_vm_user, email, AST_DATA_STRING) \
11389 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11390 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11391 USER(ast_vm_user, pager, AST_DATA_STRING) \
11392 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11393 USER(ast_vm_user, language, AST_DATA_STRING) \
11394 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11395 USER(ast_vm_user, callback, AST_DATA_STRING) \
11396 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11397 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11398 USER(ast_vm_user, exit, AST_DATA_STRING) \
11399 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11400 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11401 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11402 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11403 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11404 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11405 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11406 #endif
11407
11408 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11409
11410 #define DATA_EXPORT_VM_ZONES(ZONE) \
11411 ZONE(vm_zone, name, AST_DATA_STRING) \
11412 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11413 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11414
11415 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11416
11417
11418
11419
11420
11421
11422
11423
11424 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11425 struct ast_data *data_root, struct ast_vm_user *user)
11426 {
11427 struct ast_data *data_user, *data_zone;
11428 struct ast_data *data_state;
11429 struct vm_zone *zone = NULL;
11430 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11431 char ext_context[256] = "";
11432
11433 data_user = ast_data_add_node(data_root, "user");
11434 if (!data_user) {
11435 return -1;
11436 }
11437
11438 ast_data_add_structure(ast_vm_user, data_user, user);
11439
11440 AST_LIST_LOCK(&zones);
11441 AST_LIST_TRAVERSE(&zones, zone, list) {
11442 if (!strcmp(zone->name, user->zonetag)) {
11443 break;
11444 }
11445 }
11446 AST_LIST_UNLOCK(&zones);
11447
11448
11449 data_state = ast_data_add_node(data_user, "state");
11450 if (!data_state) {
11451 return -1;
11452 }
11453 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11454 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11455 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11456 ast_data_add_int(data_state, "newmsg", newmsg);
11457 ast_data_add_int(data_state, "oldmsg", oldmsg);
11458
11459 if (zone) {
11460 data_zone = ast_data_add_node(data_user, "zone");
11461 ast_data_add_structure(vm_zone, data_zone, zone);
11462 }
11463
11464 if (!ast_data_search_match(search, data_user)) {
11465 ast_data_remove_node(data_root, data_user);
11466 }
11467
11468 return 0;
11469 }
11470
11471 static int vm_users_data_provider_get(const struct ast_data_search *search,
11472 struct ast_data *data_root)
11473 {
11474 struct ast_vm_user *user;
11475
11476 AST_LIST_LOCK(&users);
11477 AST_LIST_TRAVERSE(&users, user, list) {
11478 vm_users_data_provider_get_helper(search, data_root, user);
11479 }
11480 AST_LIST_UNLOCK(&users);
11481
11482 return 0;
11483 }
11484
11485 static const struct ast_data_handler vm_users_data_provider = {
11486 .version = AST_DATA_HANDLER_VERSION,
11487 .get = vm_users_data_provider_get
11488 };
11489
11490 static const struct ast_data_entry vm_data_providers[] = {
11491 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11492 };
11493
11494 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11495 {
11496 int new = 0, old = 0, urgent = 0;
11497
11498 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11499
11500 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11501 mwi_sub->old_urgent = urgent;
11502 mwi_sub->old_new = new;
11503 mwi_sub->old_old = old;
11504 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11505 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11506 }
11507 }
11508
11509 static void poll_subscribed_mailboxes(void)
11510 {
11511 struct mwi_sub *mwi_sub;
11512
11513 AST_RWLIST_RDLOCK(&mwi_subs);
11514 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11515 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11516 poll_subscribed_mailbox(mwi_sub);
11517 }
11518 }
11519 AST_RWLIST_UNLOCK(&mwi_subs);
11520 }
11521
11522 static void *mb_poll_thread(void *data)
11523 {
11524 while (poll_thread_run) {
11525 struct timespec ts = { 0, };
11526 struct timeval wait;
11527
11528 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11529 ts.tv_sec = wait.tv_sec;
11530 ts.tv_nsec = wait.tv_usec * 1000;
11531
11532 ast_mutex_lock(&poll_lock);
11533 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11534 ast_mutex_unlock(&poll_lock);
11535
11536 if (!poll_thread_run)
11537 break;
11538
11539 poll_subscribed_mailboxes();
11540 }
11541
11542 return NULL;
11543 }
11544
11545 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11546 {
11547 ast_free(mwi_sub);
11548 }
11549
11550 static int handle_unsubscribe(void *datap)
11551 {
11552 struct mwi_sub *mwi_sub;
11553 uint32_t *uniqueid = datap;
11554
11555 AST_RWLIST_WRLOCK(&mwi_subs);
11556 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11557 if (mwi_sub->uniqueid == *uniqueid) {
11558 AST_LIST_REMOVE_CURRENT(entry);
11559 break;
11560 }
11561 }
11562 AST_RWLIST_TRAVERSE_SAFE_END
11563 AST_RWLIST_UNLOCK(&mwi_subs);
11564
11565 if (mwi_sub)
11566 mwi_sub_destroy(mwi_sub);
11567
11568 ast_free(uniqueid);
11569 return 0;
11570 }
11571
11572 static int handle_subscribe(void *datap)
11573 {
11574 unsigned int len;
11575 struct mwi_sub *mwi_sub;
11576 struct mwi_sub_task *p = datap;
11577
11578 len = sizeof(*mwi_sub);
11579 if (!ast_strlen_zero(p->mailbox))
11580 len += strlen(p->mailbox);
11581
11582 if (!ast_strlen_zero(p->context))
11583 len += strlen(p->context) + 1;
11584
11585 if (!(mwi_sub = ast_calloc(1, len)))
11586 return -1;
11587
11588 mwi_sub->uniqueid = p->uniqueid;
11589 if (!ast_strlen_zero(p->mailbox))
11590 strcpy(mwi_sub->mailbox, p->mailbox);
11591
11592 if (!ast_strlen_zero(p->context)) {
11593 strcat(mwi_sub->mailbox, "@");
11594 strcat(mwi_sub->mailbox, p->context);
11595 }
11596
11597 AST_RWLIST_WRLOCK(&mwi_subs);
11598 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11599 AST_RWLIST_UNLOCK(&mwi_subs);
11600 ast_free((void *) p->mailbox);
11601 ast_free((void *) p->context);
11602 ast_free(p);
11603 poll_subscribed_mailbox(mwi_sub);
11604 return 0;
11605 }
11606
11607 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11608 {
11609 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11610
11611 if (!uniqueid) {
11612 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11613 return;
11614 }
11615
11616 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11617 ast_free(uniqueid);
11618 return;
11619 }
11620
11621 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11622 ast_free(uniqueid);
11623 return;
11624 }
11625
11626 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11627 *uniqueid = u;
11628 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11629 ast_free(uniqueid);
11630 }
11631 }
11632
11633 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11634 {
11635 struct mwi_sub_task *mwist;
11636
11637 if (ast_event_get_type(event) != AST_EVENT_SUB)
11638 return;
11639
11640 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11641 return;
11642
11643 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11644 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11645 return;
11646 }
11647 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11648 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11649 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11650
11651 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11652 ast_free(mwist);
11653 }
11654 }
11655
11656 static void start_poll_thread(void)
11657 {
11658 int errcode;
11659 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11660 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11661 AST_EVENT_IE_END);
11662
11663 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11664 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11665 AST_EVENT_IE_END);
11666
11667 if (mwi_sub_sub)
11668 ast_event_report_subs(mwi_sub_sub);
11669
11670 poll_thread_run = 1;
11671
11672 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11673 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11674 }
11675 }
11676
11677 static void stop_poll_thread(void)
11678 {
11679 poll_thread_run = 0;
11680
11681 if (mwi_sub_sub) {
11682 ast_event_unsubscribe(mwi_sub_sub);
11683 mwi_sub_sub = NULL;
11684 }
11685
11686 if (mwi_unsub_sub) {
11687 ast_event_unsubscribe(mwi_unsub_sub);
11688 mwi_unsub_sub = NULL;
11689 }
11690
11691 ast_mutex_lock(&poll_lock);
11692 ast_cond_signal(&poll_cond);
11693 ast_mutex_unlock(&poll_lock);
11694
11695 pthread_join(poll_thread, NULL);
11696
11697 poll_thread = AST_PTHREADT_NULL;
11698 }
11699
11700
11701 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11702 {
11703 struct ast_vm_user *vmu = NULL;
11704 const char *id = astman_get_header(m, "ActionID");
11705 char actionid[128] = "";
11706
11707 if (!ast_strlen_zero(id))
11708 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11709
11710 AST_LIST_LOCK(&users);
11711
11712 if (AST_LIST_EMPTY(&users)) {
11713 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11714 AST_LIST_UNLOCK(&users);
11715 return RESULT_SUCCESS;
11716 }
11717
11718 astman_send_ack(s, m, "Voicemail user list will follow");
11719
11720 AST_LIST_TRAVERSE(&users, vmu, list) {
11721 char dirname[256];
11722
11723 #ifdef IMAP_STORAGE
11724 int new, old;
11725 inboxcount(vmu->mailbox, &new, &old);
11726 #endif
11727
11728 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11729 astman_append(s,
11730 "%s"
11731 "Event: VoicemailUserEntry\r\n"
11732 "VMContext: %s\r\n"
11733 "VoiceMailbox: %s\r\n"
11734 "Fullname: %s\r\n"
11735 "Email: %s\r\n"
11736 "Pager: %s\r\n"
11737 "ServerEmail: %s\r\n"
11738 "MailCommand: %s\r\n"
11739 "Language: %s\r\n"
11740 "TimeZone: %s\r\n"
11741 "Callback: %s\r\n"
11742 "Dialout: %s\r\n"
11743 "UniqueID: %s\r\n"
11744 "ExitContext: %s\r\n"
11745 "SayDurationMinimum: %d\r\n"
11746 "SayEnvelope: %s\r\n"
11747 "SayCID: %s\r\n"
11748 "AttachMessage: %s\r\n"
11749 "AttachmentFormat: %s\r\n"
11750 "DeleteMessage: %s\r\n"
11751 "VolumeGain: %.2f\r\n"
11752 "CanReview: %s\r\n"
11753 "CallOperator: %s\r\n"
11754 "MaxMessageCount: %d\r\n"
11755 "MaxMessageLength: %d\r\n"
11756 "NewMessageCount: %d\r\n"
11757 #ifdef IMAP_STORAGE
11758 "OldMessageCount: %d\r\n"
11759 "IMAPUser: %s\r\n"
11760 #endif
11761 "\r\n",
11762 actionid,
11763 vmu->context,
11764 vmu->mailbox,
11765 vmu->fullname,
11766 vmu->email,
11767 vmu->pager,
11768 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
11769 mailcmd,
11770 vmu->language,
11771 vmu->zonetag,
11772 vmu->callback,
11773 vmu->dialout,
11774 vmu->uniqueid,
11775 vmu->exit,
11776 vmu->saydurationm,
11777 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11778 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11779 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11780 vmu->attachfmt,
11781 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11782 vmu->volgain,
11783 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11784 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11785 vmu->maxmsg,
11786 vmu->maxsecs,
11787 #ifdef IMAP_STORAGE
11788 new, old, vmu->imapuser
11789 #else
11790 count_messages(vmu, dirname)
11791 #endif
11792 );
11793 }
11794 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11795
11796 AST_LIST_UNLOCK(&users);
11797
11798 return RESULT_SUCCESS;
11799 }
11800
11801
11802 static void free_vm_users(void)
11803 {
11804 struct ast_vm_user *current;
11805 AST_LIST_LOCK(&users);
11806 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11807 ast_set_flag(current, VM_ALLOCED);
11808 free_user(current);
11809 }
11810 AST_LIST_UNLOCK(&users);
11811 }
11812
11813
11814 static void free_vm_zones(void)
11815 {
11816 struct vm_zone *zcur;
11817 AST_LIST_LOCK(&zones);
11818 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11819 free_zone(zcur);
11820 AST_LIST_UNLOCK(&zones);
11821 }
11822
11823 static const char *substitute_escapes(const char *value)
11824 {
11825 char *current;
11826
11827
11828 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11829
11830 ast_str_reset(str);
11831
11832
11833 for (current = (char *) value; *current; current++) {
11834 if (*current == '\\') {
11835 current++;
11836 if (!*current) {
11837 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11838 break;
11839 }
11840 switch (*current) {
11841 case '\\':
11842 ast_str_append(&str, 0, "\\");
11843 break;
11844 case 'r':
11845 ast_str_append(&str, 0, "\r");
11846 break;
11847 case 'n':
11848 #ifdef IMAP_STORAGE
11849 if (!str->used || str->str[str->used - 1] != '\r') {
11850 ast_str_append(&str, 0, "\r");
11851 }
11852 #endif
11853 ast_str_append(&str, 0, "\n");
11854 break;
11855 case 't':
11856 ast_str_append(&str, 0, "\t");
11857 break;
11858 default:
11859 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11860 break;
11861 }
11862 } else {
11863 ast_str_append(&str, 0, "%c", *current);
11864 }
11865 }
11866
11867 return ast_str_buffer(str);
11868 }
11869
11870 static int load_config(int reload)
11871 {
11872 struct ast_config *cfg, *ucfg;
11873 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11874 int res;
11875
11876 ast_unload_realtime("voicemail");
11877 ast_unload_realtime("voicemail_data");
11878
11879 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11880 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11881 return 0;
11882 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11883 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11884 ucfg = NULL;
11885 }
11886 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11887 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11888 ast_config_destroy(ucfg);
11889 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11890 return 0;
11891 }
11892 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11893 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11894 return 0;
11895 } else {
11896 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11897 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11898 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11899 ucfg = NULL;
11900 }
11901 }
11902
11903 res = actual_load_config(reload, cfg, ucfg);
11904
11905 ast_config_destroy(cfg);
11906 ast_config_destroy(ucfg);
11907
11908 return res;
11909 }
11910
11911 #ifdef TEST_FRAMEWORK
11912 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11913 {
11914 ast_unload_realtime("voicemail");
11915 ast_unload_realtime("voicemail_data");
11916 return actual_load_config(reload, cfg, ucfg);
11917 }
11918 #endif
11919
11920 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11921 {
11922 struct ast_vm_user *current;
11923 char *cat;
11924 struct ast_variable *var;
11925 const char *val;
11926 char *q, *stringp, *tmp;
11927 int x;
11928 unsigned int tmpadsi[4];
11929 char secretfn[PATH_MAX] = "";
11930
11931 #ifdef IMAP_STORAGE
11932 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11933 #endif
11934
11935 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11936 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11937 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11938 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11939 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11940
11941
11942 free_vm_users();
11943
11944
11945 free_vm_zones();
11946
11947 AST_LIST_LOCK(&users);
11948
11949 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11950 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11951
11952 if (cfg) {
11953
11954
11955 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11956 val = "default";
11957 ast_copy_string(userscontext, val, sizeof(userscontext));
11958
11959 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11960 val = "yes";
11961 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11962
11963 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11964 val = "no";
11965 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11966
11967 volgain = 0.0;
11968 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11969 sscanf(val, "%30lf", &volgain);
11970
11971 #ifdef ODBC_STORAGE
11972 strcpy(odbc_database, "asterisk");
11973 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11974 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11975 }
11976 strcpy(odbc_table, "voicemessages");
11977 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11978 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11979 }
11980 #endif
11981
11982 strcpy(mailcmd, SENDMAIL);
11983 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11984 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11985
11986 maxsilence = 0;
11987 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11988 maxsilence = atoi(val);
11989 if (maxsilence > 0)
11990 maxsilence *= 1000;
11991 }
11992
11993 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11994 maxmsg = MAXMSG;
11995 } else {
11996 maxmsg = atoi(val);
11997 if (maxmsg < 0) {
11998 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11999 maxmsg = MAXMSG;
12000 } else if (maxmsg > MAXMSGLIMIT) {
12001 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
12002 maxmsg = MAXMSGLIMIT;
12003 }
12004 }
12005
12006 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
12007 maxdeletedmsg = 0;
12008 } else {
12009 if (sscanf(val, "%30d", &x) == 1)
12010 maxdeletedmsg = x;
12011 else if (ast_true(val))
12012 maxdeletedmsg = MAXMSG;
12013 else
12014 maxdeletedmsg = 0;
12015
12016 if (maxdeletedmsg < 0) {
12017 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
12018 maxdeletedmsg = MAXMSG;
12019 } else if (maxdeletedmsg > MAXMSGLIMIT) {
12020 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
12021 maxdeletedmsg = MAXMSGLIMIT;
12022 }
12023 }
12024
12025
12026 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
12027 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
12028 }
12029
12030
12031 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
12032 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
12033 }
12034
12035
12036 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
12037 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12038 pwdchange = PWDCHANGE_EXTERNAL;
12039 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
12040 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12041 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
12042 }
12043
12044
12045 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
12046 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
12047 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
12048 }
12049
12050 #ifdef IMAP_STORAGE
12051
12052 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
12053 ast_copy_string(imapserver, val, sizeof(imapserver));
12054 } else {
12055 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
12056 }
12057
12058 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
12059 ast_copy_string(imapport, val, sizeof(imapport));
12060 } else {
12061 ast_copy_string(imapport, "143", sizeof(imapport));
12062 }
12063
12064 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
12065 ast_copy_string(imapflags, val, sizeof(imapflags));
12066 }
12067
12068 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12069 ast_copy_string(authuser, val, sizeof(authuser));
12070 }
12071
12072 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12073 ast_copy_string(authpassword, val, sizeof(authpassword));
12074 }
12075
12076 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12077 if (ast_false(val))
12078 expungeonhangup = 0;
12079 else
12080 expungeonhangup = 1;
12081 } else {
12082 expungeonhangup = 1;
12083 }
12084
12085 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12086 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12087 } else {
12088 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12089 }
12090 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12091 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12092 }
12093 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12094 imapgreetings = ast_true(val);
12095 } else {
12096 imapgreetings = 0;
12097 }
12098 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12099 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12100 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12101
12102 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12103 } else {
12104 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12105 }
12106
12107
12108
12109
12110
12111 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12112 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12113 } else {
12114 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12115 }
12116
12117 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12118 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12119 } else {
12120 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12121 }
12122
12123 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12124 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12125 } else {
12126 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12127 }
12128
12129 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12130 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12131 } else {
12132 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12133 }
12134
12135
12136 imapversion++;
12137 #endif
12138
12139 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12140 ast_copy_string(externnotify, val, sizeof(externnotify));
12141 ast_debug(1, "found externnotify: %s\n", externnotify);
12142 } else {
12143 externnotify[0] = '\0';
12144 }
12145
12146
12147 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12148 ast_debug(1, "Enabled SMDI voicemail notification\n");
12149 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12150 smdi_iface = ast_smdi_interface_find(val);
12151 } else {
12152 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12153 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12154 }
12155 if (!smdi_iface) {
12156 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12157 }
12158 }
12159
12160
12161 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12162 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12163 silencethreshold = atoi(val);
12164
12165 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12166 val = ASTERISK_USERNAME;
12167 ast_copy_string(serveremail, val, sizeof(serveremail));
12168
12169 vmmaxsecs = 0;
12170 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12171 if (sscanf(val, "%30d", &x) == 1) {
12172 vmmaxsecs = x;
12173 } else {
12174 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12175 }
12176 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12177 static int maxmessage_deprecate = 0;
12178 if (maxmessage_deprecate == 0) {
12179 maxmessage_deprecate = 1;
12180 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12181 }
12182 if (sscanf(val, "%30d", &x) == 1) {
12183 vmmaxsecs = x;
12184 } else {
12185 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12186 }
12187 }
12188
12189 vmminsecs = 0;
12190 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12191 if (sscanf(val, "%30d", &x) == 1) {
12192 vmminsecs = x;
12193 if (maxsilence / 1000 >= vmminsecs) {
12194 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12195 }
12196 } else {
12197 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12198 }
12199 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12200 static int maxmessage_deprecate = 0;
12201 if (maxmessage_deprecate == 0) {
12202 maxmessage_deprecate = 1;
12203 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12204 }
12205 if (sscanf(val, "%30d", &x) == 1) {
12206 vmminsecs = x;
12207 if (maxsilence / 1000 >= vmminsecs) {
12208 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12209 }
12210 } else {
12211 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12212 }
12213 }
12214
12215 val = ast_variable_retrieve(cfg, "general", "format");
12216 if (!val) {
12217 val = "wav";
12218 } else {
12219 tmp = ast_strdupa(val);
12220 val = ast_format_str_reduce(tmp);
12221 if (!val) {
12222 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12223 val = "wav";
12224 }
12225 }
12226 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12227
12228 skipms = 3000;
12229 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12230 if (sscanf(val, "%30d", &x) == 1) {
12231 maxgreet = x;
12232 } else {
12233 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12234 }
12235 }
12236
12237 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12238 if (sscanf(val, "%30d", &x) == 1) {
12239 skipms = x;
12240 } else {
12241 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12242 }
12243 }
12244
12245 maxlogins = 3;
12246 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12247 if (sscanf(val, "%30d", &x) == 1) {
12248 maxlogins = x;
12249 } else {
12250 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12251 }
12252 }
12253
12254 minpassword = MINPASSWORD;
12255 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12256 if (sscanf(val, "%30d", &x) == 1) {
12257 minpassword = x;
12258 } else {
12259 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12260 }
12261 }
12262
12263
12264 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12265 val = "no";
12266 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12267
12268
12269 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12270 val = "no";
12271 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12272
12273 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12274 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12275 stringp = ast_strdupa(val);
12276 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12277 if (!ast_strlen_zero(stringp)) {
12278 q = strsep(&stringp, ",");
12279 while ((*q == ' ')||(*q == '\t'))
12280 q++;
12281 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12282 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12283 } else {
12284 cidinternalcontexts[x][0] = '\0';
12285 }
12286 }
12287 }
12288 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12289 ast_debug(1, "VM Review Option disabled globally\n");
12290 val = "no";
12291 }
12292 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12293
12294
12295 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12296 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12297 val = "no";
12298 } else {
12299 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12300 }
12301 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12302 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12303 ast_debug(1, "VM next message wrap disabled globally\n");
12304 val = "no";
12305 }
12306 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12307
12308 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12309 ast_debug(1, "VM Operator break disabled globally\n");
12310 val = "no";
12311 }
12312 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12313
12314 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12315 ast_debug(1, "VM CID Info before msg disabled globally\n");
12316 val = "no";
12317 }
12318 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12319
12320 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12321 ast_debug(1, "Send Voicemail msg disabled globally\n");
12322 val = "no";
12323 }
12324 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12325
12326 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12327 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12328 val = "yes";
12329 }
12330 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12331
12332 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12333 ast_debug(1, "Move Heard enabled globally\n");
12334 val = "yes";
12335 }
12336 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12337
12338 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12339 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12340 val = "no";
12341 }
12342 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12343
12344 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12345 ast_debug(1, "Duration info before msg enabled globally\n");
12346 val = "yes";
12347 }
12348 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12349
12350 saydurationminfo = 2;
12351 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12352 if (sscanf(val, "%30d", &x) == 1) {
12353 saydurationminfo = x;
12354 } else {
12355 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12356 }
12357 }
12358
12359 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12360 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12361 val = "no";
12362 }
12363 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12364
12365 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12366 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12367 ast_debug(1, "found dialout context: %s\n", dialcontext);
12368 } else {
12369 dialcontext[0] = '\0';
12370 }
12371
12372 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12373 ast_copy_string(callcontext, val, sizeof(callcontext));
12374 ast_debug(1, "found callback context: %s\n", callcontext);
12375 } else {
12376 callcontext[0] = '\0';
12377 }
12378
12379 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12380 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12381 ast_debug(1, "found operator context: %s\n", exitcontext);
12382 } else {
12383 exitcontext[0] = '\0';
12384 }
12385
12386
12387 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12388 ast_copy_string(vm_password, val, sizeof(vm_password));
12389 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12390 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12391 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12392 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12393 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12394 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12395 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12396 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12397 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12398 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12399 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12400 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12401 }
12402 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12403 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12404 }
12405
12406 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12407 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12408 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12409 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12410 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12411 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12412 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12413 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12414 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12415 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12416
12417 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12418 val = "no";
12419 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12420
12421 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12422 val = "voicemail.conf";
12423 }
12424 if (!(strcmp(val, "spooldir"))) {
12425 passwordlocation = OPT_PWLOC_SPOOLDIR;
12426 } else {
12427 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12428 }
12429
12430 poll_freq = DEFAULT_POLL_FREQ;
12431 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12432 if (sscanf(val, "%30u", &poll_freq) != 1) {
12433 poll_freq = DEFAULT_POLL_FREQ;
12434 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12435 }
12436 }
12437
12438 poll_mailboxes = 0;
12439 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12440 poll_mailboxes = ast_true(val);
12441
12442 memset(fromstring, 0, sizeof(fromstring));
12443 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12444 strcpy(charset, "ISO-8859-1");
12445 if (emailbody) {
12446 ast_free(emailbody);
12447 emailbody = NULL;
12448 }
12449 if (emailsubject) {
12450 ast_free(emailsubject);
12451 emailsubject = NULL;
12452 }
12453 if (pagerbody) {
12454 ast_free(pagerbody);
12455 pagerbody = NULL;
12456 }
12457 if (pagersubject) {
12458 ast_free(pagersubject);
12459 pagersubject = NULL;
12460 }
12461 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12462 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12463 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12464 ast_copy_string(fromstring, val, sizeof(fromstring));
12465 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12466 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12467 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12468 ast_copy_string(charset, val, sizeof(charset));
12469 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12470 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12471 for (x = 0; x < 4; x++) {
12472 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12473 }
12474 }
12475 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12476 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12477 for (x = 0; x < 4; x++) {
12478 memcpy(&adsisec[x], &tmpadsi[x], 1);
12479 }
12480 }
12481 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12482 if (atoi(val)) {
12483 adsiver = atoi(val);
12484 }
12485 }
12486 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12487 ast_copy_string(zonetag, val, sizeof(zonetag));
12488 }
12489 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12490 ast_copy_string(locale, val, sizeof(locale));
12491 }
12492 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12493 emailsubject = ast_strdup(substitute_escapes(val));
12494 }
12495 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12496 emailbody = ast_strdup(substitute_escapes(val));
12497 }
12498 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12499 pagersubject = ast_strdup(substitute_escapes(val));
12500 }
12501 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12502 pagerbody = ast_strdup(substitute_escapes(val));
12503 }
12504
12505
12506 if (ucfg) {
12507 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12508 if (!strcasecmp(cat, "general")) {
12509 continue;
12510 }
12511 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12512 continue;
12513 if ((current = find_or_create(userscontext, cat))) {
12514 populate_defaults(current);
12515 apply_options_full(current, ast_variable_browse(ucfg, cat));
12516 ast_copy_string(current->context, userscontext, sizeof(current->context));
12517 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12518 current->passwordlocation = OPT_PWLOC_USERSCONF;
12519 }
12520
12521 switch (current->passwordlocation) {
12522 case OPT_PWLOC_SPOOLDIR:
12523 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12524 read_password_from_file(secretfn, current->password, sizeof(current->password));
12525 }
12526 }
12527 }
12528 }
12529
12530
12531 cat = ast_category_browse(cfg, NULL);
12532 while (cat) {
12533 if (strcasecmp(cat, "general")) {
12534 var = ast_variable_browse(cfg, cat);
12535 if (strcasecmp(cat, "zonemessages")) {
12536
12537 while (var) {
12538 append_mailbox(cat, var->name, var->value);
12539 var = var->next;
12540 }
12541 } else {
12542
12543 while (var) {
12544 struct vm_zone *z;
12545 if ((z = ast_malloc(sizeof(*z)))) {
12546 char *msg_format, *tzone;
12547 msg_format = ast_strdupa(var->value);
12548 tzone = strsep(&msg_format, "|,");
12549 if (msg_format) {
12550 ast_copy_string(z->name, var->name, sizeof(z->name));
12551 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12552 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12553 AST_LIST_LOCK(&zones);
12554 AST_LIST_INSERT_HEAD(&zones, z, list);
12555 AST_LIST_UNLOCK(&zones);
12556 } else {
12557 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12558 ast_free(z);
12559 }
12560 } else {
12561 AST_LIST_UNLOCK(&users);
12562 return -1;
12563 }
12564 var = var->next;
12565 }
12566 }
12567 }
12568 cat = ast_category_browse(cfg, cat);
12569 }
12570
12571 AST_LIST_UNLOCK(&users);
12572
12573 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12574 start_poll_thread();
12575 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12576 stop_poll_thread();;
12577
12578 return 0;
12579 } else {
12580 AST_LIST_UNLOCK(&users);
12581 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12582 return 0;
12583 }
12584 }
12585
12586 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12587 {
12588 int res = -1;
12589 char dir[PATH_MAX];
12590 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12591 ast_debug(2, "About to try retrieving name file %s\n", dir);
12592 RETRIEVE(dir, -1, mailbox, context);
12593 if (ast_fileexists(dir, NULL, NULL)) {
12594 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12595 }
12596 DISPOSE(dir, -1);
12597 return res;
12598 }
12599
12600 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12601 struct ast_config *pwconf;
12602 struct ast_flags config_flags = { 0 };
12603
12604 pwconf = ast_config_load(secretfn, config_flags);
12605 if (valid_config(pwconf)) {
12606 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12607 if (val) {
12608 ast_copy_string(password, val, passwordlen);
12609 ast_config_destroy(pwconf);
12610 return;
12611 }
12612 ast_config_destroy(pwconf);
12613 }
12614 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12615 }
12616
12617 static int write_password_to_file(const char *secretfn, const char *password) {
12618 struct ast_config *conf;
12619 struct ast_category *cat;
12620 struct ast_variable *var;
12621 int res = -1;
12622
12623 if (!(conf = ast_config_new())) {
12624 ast_log(LOG_ERROR, "Error creating new config structure\n");
12625 return res;
12626 }
12627 if (!(cat = ast_category_new("general", "", 1))) {
12628 ast_log(LOG_ERROR, "Error creating new category structure\n");
12629 ast_config_destroy(conf);
12630 return res;
12631 }
12632 if (!(var = ast_variable_new("password", password, ""))) {
12633 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12634 ast_config_destroy(conf);
12635 ast_category_destroy(cat);
12636 return res;
12637 }
12638 ast_category_append(conf, cat);
12639 ast_variable_append(cat, var);
12640 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12641 res = 0;
12642 } else {
12643 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12644 }
12645
12646 ast_config_destroy(conf);
12647 return res;
12648 }
12649
12650 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12651 {
12652 char *context;
12653 char *args_copy;
12654 int res;
12655
12656 if (ast_strlen_zero(data)) {
12657 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12658 return -1;
12659 }
12660
12661 args_copy = ast_strdupa(data);
12662 if ((context = strchr(args_copy, '@'))) {
12663 *context++ = '\0';
12664 } else {
12665 context = "default";
12666 }
12667
12668 if ((res = sayname(chan, args_copy, context) < 0)) {
12669 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12670 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12671 if (!res) {
12672 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12673 }
12674 }
12675
12676 return res;
12677 }
12678
12679 #ifdef TEST_FRAMEWORK
12680 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12681 {
12682 return 0;
12683 }
12684
12685 static struct ast_frame *fake_read(struct ast_channel *ast)
12686 {
12687 return &ast_null_frame;
12688 }
12689
12690 AST_TEST_DEFINE(test_voicemail_vmsayname)
12691 {
12692 char dir[PATH_MAX];
12693 char dir2[PATH_MAX];
12694 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12695 static const char TEST_EXTENSION[] = "1234";
12696
12697 struct ast_channel *test_channel1 = NULL;
12698 int res = -1;
12699
12700 static const struct ast_channel_tech fake_tech = {
12701 .write = fake_write,
12702 .read = fake_read,
12703 };
12704
12705 switch (cmd) {
12706 case TEST_INIT:
12707 info->name = "vmsayname_exec";
12708 info->category = "/apps/app_voicemail/";
12709 info->summary = "Vmsayname unit test";
12710 info->description =
12711 "This tests passing various parameters to vmsayname";
12712 return AST_TEST_NOT_RUN;
12713 case TEST_EXECUTE:
12714 break;
12715 }
12716
12717 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12718 NULL, NULL, 0, 0, "TestChannel1"))) {
12719 goto exit_vmsayname_test;
12720 }
12721
12722
12723 test_channel1->nativeformats = AST_FORMAT_GSM;
12724 test_channel1->writeformat = AST_FORMAT_GSM;
12725 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12726 test_channel1->readformat = AST_FORMAT_GSM;
12727 test_channel1->rawreadformat = AST_FORMAT_GSM;
12728 test_channel1->tech = &fake_tech;
12729
12730 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12731 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12732 if (!(res = vmsayname_exec(test_channel1, dir))) {
12733 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12734 if (ast_fileexists(dir, NULL, NULL)) {
12735 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12736 res = -1;
12737 goto exit_vmsayname_test;
12738 } else {
12739
12740 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12741 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12742 goto exit_vmsayname_test;
12743 }
12744 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12745 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12746
12747 if ((res = symlink(dir, dir2))) {
12748 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12749 goto exit_vmsayname_test;
12750 }
12751 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12752 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12753 res = vmsayname_exec(test_channel1, dir);
12754
12755
12756 unlink(dir2);
12757 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12758 rmdir(dir2);
12759 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12760 rmdir(dir2);
12761 }
12762 }
12763
12764 exit_vmsayname_test:
12765
12766 if (test_channel1) {
12767 ast_hangup(test_channel1);
12768 }
12769
12770 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12771 }
12772
12773 AST_TEST_DEFINE(test_voicemail_msgcount)
12774 {
12775 int i, j, res = AST_TEST_PASS, syserr;
12776 struct ast_vm_user *vmu;
12777 struct ast_vm_user svm;
12778 struct vm_state vms;
12779 #ifdef IMAP_STORAGE
12780 struct ast_channel *chan = NULL;
12781 #endif
12782 struct {
12783 char dir[256];
12784 char file[256];
12785 char txtfile[256];
12786 } tmp[3];
12787 char syscmd[256];
12788 const char origweasels[] = "tt-weasels";
12789 const char testcontext[] = "test";
12790 const char testmailbox[] = "00000000";
12791 const char testspec[] = "00000000@test";
12792 FILE *txt;
12793 int new, old, urgent;
12794 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12795 const int folder2mbox[3] = { 1, 11, 0 };
12796 const int expected_results[3][12] = {
12797
12798 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12799 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12800 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12801 };
12802
12803 switch (cmd) {
12804 case TEST_INIT:
12805 info->name = "test_voicemail_msgcount";
12806 info->category = "/apps/app_voicemail/";
12807 info->summary = "Test Voicemail status checks";
12808 info->description =
12809 "Verify that message counts are correct when retrieved through the public API";
12810 return AST_TEST_NOT_RUN;
12811 case TEST_EXECUTE:
12812 break;
12813 }
12814
12815
12816 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12817 if ((syserr = ast_safe_system(syscmd))) {
12818 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12819 syserr > 0 ? strerror(syserr) : "unable to fork()");
12820 return AST_TEST_FAIL;
12821 }
12822
12823 #ifdef IMAP_STORAGE
12824 if (!(chan = ast_dummy_channel_alloc())) {
12825 ast_test_status_update(test, "Unable to create dummy channel\n");
12826 return AST_TEST_FAIL;
12827 }
12828 #endif
12829
12830 if (!(vmu = find_user(&svm, testcontext, testmailbox)) &&
12831 !(vmu = find_or_create(testcontext, testmailbox))) {
12832 ast_test_status_update(test, "Cannot create vmu structure\n");
12833 ast_unreplace_sigchld();
12834 #ifdef IMAP_STORAGE
12835 chan = ast_channel_unref(chan);
12836 #endif
12837 return AST_TEST_FAIL;
12838 }
12839
12840 populate_defaults(vmu);
12841 memset(&vms, 0, sizeof(vms));
12842
12843
12844 for (i = 0; i < 3; i++) {
12845 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12846 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12847 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12848
12849 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12850 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12851 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12852 if ((syserr = ast_safe_system(syscmd))) {
12853 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12854 syserr > 0 ? strerror(syserr) : "unable to fork()");
12855 ast_unreplace_sigchld();
12856 #ifdef IMAP_STORAGE
12857 chan = ast_channel_unref(chan);
12858 #endif
12859 return AST_TEST_FAIL;
12860 }
12861 }
12862
12863 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12864 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12865 fclose(txt);
12866 } else {
12867 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12868 res = AST_TEST_FAIL;
12869 break;
12870 }
12871 open_mailbox(&vms, vmu, folder2mbox[i]);
12872 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12873
12874
12875 for (j = 0; j < 3; j++) {
12876
12877 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12878 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12879 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12880 res = AST_TEST_FAIL;
12881 }
12882 }
12883
12884 new = old = urgent = 0;
12885 if (ast_app_inboxcount(testspec, &new, &old)) {
12886 ast_test_status_update(test, "inboxcount returned failure\n");
12887 res = AST_TEST_FAIL;
12888 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12889 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12890 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12891 res = AST_TEST_FAIL;
12892 }
12893
12894 new = old = urgent = 0;
12895 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12896 ast_test_status_update(test, "inboxcount2 returned failure\n");
12897 res = AST_TEST_FAIL;
12898 } else if (old != expected_results[i][6 + 0] ||
12899 urgent != expected_results[i][6 + 1] ||
12900 new != expected_results[i][6 + 2] ) {
12901 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12902 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12903 res = AST_TEST_FAIL;
12904 }
12905
12906 new = old = urgent = 0;
12907 for (j = 0; j < 3; j++) {
12908 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12909 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12910 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12911 res = AST_TEST_FAIL;
12912 }
12913 }
12914 }
12915
12916 for (i = 0; i < 3; i++) {
12917
12918
12919
12920 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12921 DISPOSE(tmp[i].dir, 0);
12922 }
12923
12924 if (vms.deleted) {
12925 ast_free(vms.deleted);
12926 }
12927 if (vms.heard) {
12928 ast_free(vms.heard);
12929 }
12930
12931 #ifdef IMAP_STORAGE
12932 chan = ast_channel_unref(chan);
12933 #endif
12934
12935
12936 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12937 if ((syserr = ast_safe_system(syscmd))) {
12938 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12939 syserr > 0 ? strerror(syserr) : "unable to fork()");
12940 }
12941
12942 return res;
12943 }
12944
12945 AST_TEST_DEFINE(test_voicemail_notify_endl)
12946 {
12947 int res = AST_TEST_PASS;
12948 char testcontext[] = "test";
12949 char testmailbox[] = "00000000";
12950 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12951 char attach[256], attach2[256];
12952 char buf[256] = "";
12953 struct ast_channel *chan = NULL;
12954 struct ast_vm_user *vmu, vmus = {
12955 .flags = 0,
12956 };
12957 FILE *file;
12958 struct {
12959 char *name;
12960 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12961 void *location;
12962 union {
12963 int intval;
12964 char *strval;
12965 } u;
12966 } test_items[] = {
12967 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12968 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12969 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12970 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12971 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12972 { "attach2", STRPTR, attach2, .u.strval = "" },
12973 { "attach", STRPTR, attach, .u.strval = "" },
12974 };
12975 int which;
12976
12977 switch (cmd) {
12978 case TEST_INIT:
12979 info->name = "test_voicemail_notify_endl";
12980 info->category = "/apps/app_voicemail/";
12981 info->summary = "Test Voicemail notification end-of-line";
12982 info->description =
12983 "Verify that notification emails use a consistent end-of-line character";
12984 return AST_TEST_NOT_RUN;
12985 case TEST_EXECUTE:
12986 break;
12987 }
12988
12989 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12990 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12991
12992 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12993 !(vmu = find_or_create(testcontext, testmailbox))) {
12994 ast_test_status_update(test, "Cannot create vmu structure\n");
12995 return AST_TEST_NOT_RUN;
12996 }
12997
12998 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12999 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
13000 return AST_TEST_NOT_RUN;
13001 }
13002
13003 populate_defaults(vmu);
13004 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
13005 #ifdef IMAP_STORAGE
13006
13007 #endif
13008
13009 file = tmpfile();
13010 for (which = 0; which < ARRAY_LEN(test_items); which++) {
13011
13012 rewind(file);
13013 if (ftruncate(fileno(file), 0)) {
13014 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
13015 res = AST_TEST_FAIL;
13016 break;
13017 }
13018
13019
13020 if (test_items[which].type == INT) {
13021 *((int *) test_items[which].location) = test_items[which].u.intval;
13022 } else if (test_items[which].type == FLAGVAL) {
13023 if (ast_test_flag(vmu, test_items[which].u.intval)) {
13024 ast_clear_flag(vmu, test_items[which].u.intval);
13025 } else {
13026 ast_set_flag(vmu, test_items[which].u.intval);
13027 }
13028 } else if (test_items[which].type == STATIC) {
13029 strcpy(test_items[which].location, test_items[which].u.strval);
13030 } else if (test_items[which].type == STRPTR) {
13031 test_items[which].location = test_items[which].u.strval;
13032 }
13033
13034 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
13035 rewind(file);
13036 while (fgets(buf, sizeof(buf), file)) {
13037 if (
13038 #ifdef IMAP_STORAGE
13039 buf[strlen(buf) - 2] != '\r'
13040 #else
13041 buf[strlen(buf) - 2] == '\r'
13042 #endif
13043 || buf[strlen(buf) - 1] != '\n') {
13044 res = AST_TEST_FAIL;
13045 }
13046 }
13047 }
13048 fclose(file);
13049 return res;
13050 }
13051
13052 AST_TEST_DEFINE(test_voicemail_load_config)
13053 {
13054 int res = AST_TEST_PASS;
13055 struct ast_vm_user *vmu;
13056 struct ast_config *cfg;
13057 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
13058 int fd;
13059 FILE *file;
13060 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
13061
13062 switch (cmd) {
13063 case TEST_INIT:
13064 info->name = "test_voicemail_load_config";
13065 info->category = "/apps/app_voicemail/";
13066 info->summary = "Test loading Voicemail config";
13067 info->description =
13068 "Verify that configuration is loaded consistently. "
13069 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13070 "some options were loaded after the mailboxes were instantiated, causing "
13071 "those options not to be set correctly.";
13072 return AST_TEST_NOT_RUN;
13073 case TEST_EXECUTE:
13074 break;
13075 }
13076
13077
13078 if ((fd = mkstemp(config_filename)) < 0) {
13079 return AST_TEST_FAIL;
13080 }
13081 if (!(file = fdopen(fd, "w"))) {
13082 close(fd);
13083 unlink(config_filename);
13084 return AST_TEST_FAIL;
13085 }
13086 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13087 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13088 fputs("00000002 => 9999,Mrs. Test\n", file);
13089 fclose(file);
13090
13091 if (!(cfg = ast_config_load(config_filename, config_flags)) || !valid_config(cfg)) {
13092 res = AST_TEST_FAIL;
13093 goto cleanup;
13094 }
13095
13096 load_config_from_memory(1, cfg, NULL);
13097 ast_config_destroy(cfg);
13098
13099 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13100 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13101 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13102
13103 AST_LIST_LOCK(&users);
13104 AST_LIST_TRAVERSE(&users, vmu, list) {
13105 if (!strcmp(vmu->mailbox, "00000001")) {
13106 if (0);
13107 CHECK(vmu, callback, "othercontext")
13108 CHECK(vmu, locale, "nl_NL.UTF-8")
13109 CHECK(vmu, zonetag, "central")
13110 } else if (!strcmp(vmu->mailbox, "00000002")) {
13111 if (0);
13112 CHECK(vmu, callback, "somecontext")
13113 CHECK(vmu, locale, "de_DE.UTF-8")
13114 CHECK(vmu, zonetag, "european")
13115 }
13116 }
13117 AST_LIST_UNLOCK(&users);
13118
13119 #undef CHECK
13120
13121
13122 load_config(1);
13123
13124 cleanup:
13125 unlink(config_filename);
13126 return res;
13127 }
13128
13129 #endif
13130
13131 static int reload(void)
13132 {
13133 return load_config(1);
13134 }
13135
13136 static int unload_module(void)
13137 {
13138 int res;
13139
13140 res = ast_unregister_application(app);
13141 res |= ast_unregister_application(app2);
13142 res |= ast_unregister_application(app3);
13143 res |= ast_unregister_application(app4);
13144 res |= ast_unregister_application(sayname_app);
13145 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13146 res |= ast_manager_unregister("VoicemailUsersList");
13147 res |= ast_data_unregister(NULL);
13148 #ifdef TEST_FRAMEWORK
13149 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13150 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13151 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13152 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13153 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13154 #endif
13155 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13156 ast_uninstall_vm_functions();
13157 ao2_ref(inprocess_container, -1);
13158
13159 if (poll_thread != AST_PTHREADT_NULL)
13160 stop_poll_thread();
13161
13162 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13163 ast_unload_realtime("voicemail");
13164 ast_unload_realtime("voicemail_data");
13165
13166 free_vm_users();
13167 free_vm_zones();
13168 return res;
13169 }
13170
13171 static int load_module(void)
13172 {
13173 int res;
13174 my_umask = umask(0);
13175 umask(my_umask);
13176
13177 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13178 return AST_MODULE_LOAD_DECLINE;
13179 }
13180
13181
13182 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13183
13184 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13185 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13186 }
13187
13188 if ((res = load_config(0)))
13189 return res;
13190
13191 res = ast_register_application_xml(app, vm_exec);
13192 res |= ast_register_application_xml(app2, vm_execmain);
13193 res |= ast_register_application_xml(app3, vm_box_exists);
13194 res |= ast_register_application_xml(app4, vmauthenticate);
13195 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13196 res |= ast_custom_function_register(&mailbox_exists_acf);
13197 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13198 #ifdef TEST_FRAMEWORK
13199 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13200 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13201 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13202 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13203 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13204 #endif
13205
13206 if (res)
13207 return res;
13208
13209 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13210 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13211
13212 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13213 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13214 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13215
13216 return res;
13217 }
13218
13219 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13220 {
13221 int cmd = 0;
13222 char destination[80] = "";
13223 int retries = 0;
13224
13225 if (!num) {
13226 ast_verb(3, "Destination number will be entered manually\n");
13227 while (retries < 3 && cmd != 't') {
13228 destination[1] = '\0';
13229 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13230 if (!cmd)
13231 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13232 if (!cmd)
13233 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13234 if (!cmd) {
13235 cmd = ast_waitfordigit(chan, 6000);
13236 if (cmd)
13237 destination[0] = cmd;
13238 }
13239 if (!cmd) {
13240 retries++;
13241 } else {
13242
13243 if (cmd < 0)
13244 return 0;
13245 if (cmd == '*') {
13246 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13247 return 0;
13248 }
13249 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13250 retries++;
13251 else
13252 cmd = 't';
13253 }
13254 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13255 }
13256 if (retries >= 3) {
13257 return 0;
13258 }
13259
13260 } else {
13261 if (option_verbose > 2)
13262 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13263 ast_copy_string(destination, num, sizeof(destination));
13264 }
13265
13266 if (!ast_strlen_zero(destination)) {
13267 if (destination[strlen(destination) -1 ] == '*')
13268 return 0;
13269 if (option_verbose > 2)
13270 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13271 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13272 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13273 chan->priority = 0;
13274 return 9;
13275 }
13276 return 0;
13277 }
13278
13279
13280
13281
13282
13283
13284
13285
13286
13287
13288
13289
13290
13291
13292 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)
13293 {
13294 int res = 0;
13295 char filename[PATH_MAX];
13296 struct ast_config *msg_cfg = NULL;
13297 const char *origtime, *context;
13298 char *name, *num;
13299 int retries = 0;
13300 char *cid;
13301 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13302
13303 vms->starting = 0;
13304
13305 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13306
13307
13308 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13309 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13310 msg_cfg = ast_config_load(filename, config_flags);
13311 DISPOSE(vms->curdir, vms->curmsg);
13312 if (!valid_config(msg_cfg)) {
13313 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13314 return 0;
13315 }
13316
13317 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13318 ast_config_destroy(msg_cfg);
13319 return 0;
13320 }
13321
13322 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13323
13324 context = ast_variable_retrieve(msg_cfg, "message", "context");
13325 if (!strncasecmp("macro", context, 5))
13326 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13327 switch (option) {
13328 case 3:
13329 if (!res)
13330 res = play_message_datetime(chan, vmu, origtime, filename);
13331 if (!res)
13332 res = play_message_callerid(chan, vms, cid, context, 0);
13333
13334 res = 't';
13335 break;
13336
13337 case 2:
13338
13339 if (ast_strlen_zero(cid))
13340 break;
13341
13342 ast_callerid_parse(cid, &name, &num);
13343 while ((res > -1) && (res != 't')) {
13344 switch (res) {
13345 case '1':
13346 if (num) {
13347
13348 res = dialout(chan, vmu, num, vmu->callback);
13349 if (res) {
13350 ast_config_destroy(msg_cfg);
13351 return 9;
13352 }
13353 } else {
13354 res = '2';
13355 }
13356 break;
13357
13358 case '2':
13359
13360 if (!ast_strlen_zero(vmu->dialout)) {
13361 res = dialout(chan, vmu, NULL, vmu->dialout);
13362 if (res) {
13363 ast_config_destroy(msg_cfg);
13364 return 9;
13365 }
13366 } else {
13367 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13368 res = ast_play_and_wait(chan, "vm-sorry");
13369 }
13370 ast_config_destroy(msg_cfg);
13371 return res;
13372 case '*':
13373 res = 't';
13374 break;
13375 case '3':
13376 case '4':
13377 case '5':
13378 case '6':
13379 case '7':
13380 case '8':
13381 case '9':
13382 case '0':
13383
13384 res = ast_play_and_wait(chan, "vm-sorry");
13385 retries++;
13386 break;
13387 default:
13388 if (num) {
13389 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13390 res = ast_play_and_wait(chan, "vm-num-i-have");
13391 if (!res)
13392 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13393 if (!res)
13394 res = ast_play_and_wait(chan, "vm-tocallnum");
13395
13396 if (!ast_strlen_zero(vmu->dialout)) {
13397 if (!res)
13398 res = ast_play_and_wait(chan, "vm-calldiffnum");
13399 }
13400 } else {
13401 res = ast_play_and_wait(chan, "vm-nonumber");
13402 if (!ast_strlen_zero(vmu->dialout)) {
13403 if (!res)
13404 res = ast_play_and_wait(chan, "vm-toenternumber");
13405 }
13406 }
13407 if (!res) {
13408 res = ast_play_and_wait(chan, "vm-star-cancel");
13409 }
13410 if (!res) {
13411 res = ast_waitfordigit(chan, 6000);
13412 }
13413 if (!res) {
13414 retries++;
13415 if (retries > 3) {
13416 res = 't';
13417 }
13418 }
13419 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13420 break;
13421
13422 }
13423 if (res == 't')
13424 res = 0;
13425 else if (res == '*')
13426 res = -1;
13427 }
13428 break;
13429
13430 case 1:
13431
13432 if (ast_strlen_zero(cid))
13433 break;
13434
13435 ast_callerid_parse(cid, &name, &num);
13436 if (!num) {
13437 ast_verb(3, "No CID number available, no reply sent\n");
13438 if (!res)
13439 res = ast_play_and_wait(chan, "vm-nonumber");
13440 ast_config_destroy(msg_cfg);
13441 return res;
13442 } else {
13443 struct ast_vm_user vmu2;
13444 if (find_user(&vmu2, vmu->context, num)) {
13445 struct leave_vm_options leave_options;
13446 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13447 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13448
13449 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13450
13451 memset(&leave_options, 0, sizeof(leave_options));
13452 leave_options.record_gain = record_gain;
13453 res = leave_voicemail(chan, mailbox, &leave_options);
13454 if (!res)
13455 res = 't';
13456 ast_config_destroy(msg_cfg);
13457 return res;
13458 } else {
13459
13460 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13461 ast_play_and_wait(chan, "vm-nobox");
13462 res = 't';
13463 ast_config_destroy(msg_cfg);
13464 return res;
13465 }
13466 }
13467 res = 0;
13468
13469 break;
13470 }
13471
13472 ast_config_destroy(msg_cfg);
13473
13474 #ifndef IMAP_STORAGE
13475 if (!res) {
13476 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13477 vms->heard[msg] = 1;
13478 res = wait_file(chan, vms, vms->fn);
13479 }
13480 #endif
13481 return res;
13482 }
13483
13484 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13485 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13486 signed char record_gain, struct vm_state *vms, char *flag)
13487 {
13488
13489 int res = 0;
13490 int cmd = 0;
13491 int max_attempts = 3;
13492 int attempts = 0;
13493 int recorded = 0;
13494 int msg_exists = 0;
13495 signed char zero_gain = 0;
13496 char tempfile[PATH_MAX];
13497 char *acceptdtmf = "#";
13498 char *canceldtmf = "";
13499 int canceleddtmf = 0;
13500
13501
13502
13503
13504 if (duration == NULL) {
13505 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13506 return -1;
13507 }
13508
13509 if (!outsidecaller)
13510 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13511 else
13512 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13513
13514 cmd = '3';
13515
13516 while ((cmd >= 0) && (cmd != 't')) {
13517 switch (cmd) {
13518 case '1':
13519 if (!msg_exists) {
13520
13521 cmd = '3';
13522 break;
13523 } else {
13524
13525 ast_verb(3, "Saving message as is\n");
13526 if (!outsidecaller)
13527 ast_filerename(tempfile, recordfile, NULL);
13528 ast_stream_and_wait(chan, "vm-msgsaved", "");
13529 if (!outsidecaller) {
13530
13531 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13532 DISPOSE(recordfile, -1);
13533 }
13534 cmd = 't';
13535 return res;
13536 }
13537 case '2':
13538
13539 ast_verb(3, "Reviewing the message\n");
13540 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13541 break;
13542 case '3':
13543 msg_exists = 0;
13544
13545 if (recorded == 1)
13546 ast_verb(3, "Re-recording the message\n");
13547 else
13548 ast_verb(3, "Recording the message\n");
13549
13550 if (recorded && outsidecaller) {
13551 cmd = ast_play_and_wait(chan, INTRO);
13552 cmd = ast_play_and_wait(chan, "beep");
13553 }
13554 recorded = 1;
13555
13556 if (record_gain)
13557 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13558 if (ast_test_flag(vmu, VM_OPERATOR))
13559 canceldtmf = "0";
13560 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13561 if (strchr(canceldtmf, cmd)) {
13562
13563 canceleddtmf = 1;
13564 }
13565 if (record_gain)
13566 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13567 if (cmd == -1) {
13568
13569 if (!outsidecaller) {
13570
13571 ast_filedelete(tempfile, NULL);
13572 }
13573 return cmd;
13574 }
13575 if (cmd == '0') {
13576 break;
13577 } else if (cmd == '*') {
13578 break;
13579 #if 0
13580 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13581
13582 ast_verb(3, "Message too short\n");
13583 cmd = ast_play_and_wait(chan, "vm-tooshort");
13584 cmd = ast_filedelete(tempfile, NULL);
13585 break;
13586 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13587
13588 ast_verb(3, "Nothing recorded\n");
13589 cmd = ast_filedelete(tempfile, NULL);
13590 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13591 if (!cmd)
13592 cmd = ast_play_and_wait(chan, "vm-speakup");
13593 break;
13594 #endif
13595 } else {
13596
13597 msg_exists = 1;
13598 cmd = 0;
13599 }
13600 break;
13601 case '4':
13602 if (outsidecaller) {
13603
13604 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13605 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13606 res = ast_play_and_wait(chan, "vm-marked-urgent");
13607 strcpy(flag, "Urgent");
13608 } else if (flag) {
13609 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13610 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
13611 strcpy(flag, "");
13612 } else {
13613 ast_play_and_wait(chan, "vm-sorry");
13614 }
13615 cmd = 0;
13616 } else {
13617 cmd = ast_play_and_wait(chan, "vm-sorry");
13618 }
13619 break;
13620 case '5':
13621 case '6':
13622 case '7':
13623 case '8':
13624 case '9':
13625 case '*':
13626 case '#':
13627 cmd = ast_play_and_wait(chan, "vm-sorry");
13628 break;
13629 #if 0
13630
13631
13632 case '*':
13633
13634 cmd = ast_play_and_wait(chan, "vm-deleted");
13635 cmd = ast_filedelete(tempfile, NULL);
13636 if (outsidecaller) {
13637 res = vm_exec(chan, NULL);
13638 return res;
13639 }
13640 else
13641 return 1;
13642 #endif
13643 case '0':
13644 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13645 cmd = ast_play_and_wait(chan, "vm-sorry");
13646 break;
13647 }
13648 if (msg_exists || recorded) {
13649 cmd = ast_play_and_wait(chan, "vm-saveoper");
13650 if (!cmd)
13651 cmd = ast_waitfordigit(chan, 3000);
13652 if (cmd == '1') {
13653 ast_filerename(tempfile, recordfile, NULL);
13654 ast_play_and_wait(chan, "vm-msgsaved");
13655 cmd = '0';
13656 } else if (cmd == '4') {
13657 if (flag) {
13658 ast_play_and_wait(chan, "vm-marked-urgent");
13659 strcpy(flag, "Urgent");
13660 }
13661 ast_play_and_wait(chan, "vm-msgsaved");
13662 cmd = '0';
13663 } else {
13664 ast_play_and_wait(chan, "vm-deleted");
13665 DELETE(tempfile, -1, tempfile, vmu);
13666 cmd = '0';
13667 }
13668 }
13669 return cmd;
13670 default:
13671
13672
13673
13674 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13675 return cmd;
13676 if (msg_exists) {
13677 cmd = ast_play_and_wait(chan, "vm-review");
13678 if (!cmd && outsidecaller) {
13679 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13680 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13681 } else if (flag) {
13682 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13683 }
13684 }
13685 } else {
13686 cmd = ast_play_and_wait(chan, "vm-torerecord");
13687 if (!cmd)
13688 cmd = ast_waitfordigit(chan, 600);
13689 }
13690
13691 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13692 cmd = ast_play_and_wait(chan, "vm-reachoper");
13693 if (!cmd)
13694 cmd = ast_waitfordigit(chan, 600);
13695 }
13696 #if 0
13697 if (!cmd)
13698 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13699 #endif
13700 if (!cmd)
13701 cmd = ast_waitfordigit(chan, 6000);
13702 if (!cmd) {
13703 attempts++;
13704 }
13705 if (attempts > max_attempts) {
13706 cmd = 't';
13707 }
13708 }
13709 }
13710 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13711
13712 ast_filedelete(tempfile, NULL);
13713 }
13714
13715 if (cmd != 't' && outsidecaller)
13716 ast_play_and_wait(chan, "vm-goodbye");
13717
13718 return cmd;
13719 }
13720
13721
13722
13723
13724
13725 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13726 .load = load_module,
13727 .unload = unload_module,
13728 .reload = reload,
13729 .nonoptreq = "res_adsi,res_smdi",
13730 );