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: 369652 $")
00095
00096 #include "asterisk/paths.h"
00097 #include <sys/time.h>
00098 #include <sys/stat.h>
00099 #include <sys/mman.h>
00100 #include <time.h>
00101 #include <dirent.h>
00102 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00103 #include <sys/wait.h>
00104 #endif
00105
00106 #include "asterisk/logger.h"
00107 #include "asterisk/lock.h"
00108 #include "asterisk/file.h"
00109 #include "asterisk/channel.h"
00110 #include "asterisk/pbx.h"
00111 #include "asterisk/config.h"
00112 #include "asterisk/say.h"
00113 #include "asterisk/module.h"
00114 #include "asterisk/adsi.h"
00115 #include "asterisk/app.h"
00116 #include "asterisk/manager.h"
00117 #include "asterisk/dsp.h"
00118 #include "asterisk/localtime.h"
00119 #include "asterisk/cli.h"
00120 #include "asterisk/utils.h"
00121 #include "asterisk/stringfields.h"
00122 #include "asterisk/smdi.h"
00123 #include "asterisk/astobj2.h"
00124 #include "asterisk/event.h"
00125 #include "asterisk/taskprocessor.h"
00126 #include "asterisk/test.h"
00127
00128 #ifdef ODBC_STORAGE
00129 #include "asterisk/res_odbc.h"
00130 #endif
00131
00132 #ifdef IMAP_STORAGE
00133 #include "asterisk/threadstorage.h"
00134 #endif
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 #ifdef IMAP_STORAGE
00375 static char imapserver[48];
00376 static char imapport[8];
00377 static char imapflags[128];
00378 static char imapfolder[64];
00379 static char imapparentfolder[64] = "\0";
00380 static char greetingfolder[64];
00381 static char authuser[32];
00382 static char authpassword[42];
00383 static int imapversion = 1;
00384
00385 static int expungeonhangup = 1;
00386 static int imapgreetings = 0;
00387 static char delimiter = '\0';
00388
00389 struct vm_state;
00390 struct ast_vm_user;
00391
00392 AST_THREADSTORAGE(ts_vmstate);
00393
00394
00395 static int init_mailstream(struct vm_state *vms, int box);
00396 static void write_file(char *filename, char *buffer, unsigned long len);
00397 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00398 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00399 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00400 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00401 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00402 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00403 static void vmstate_insert(struct vm_state *vms);
00404 static void vmstate_delete(struct vm_state *vms);
00405 static void set_update(MAILSTREAM * stream);
00406 static void init_vm_state(struct vm_state *vms);
00407 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00408 static void get_mailbox_delimiter(MAILSTREAM *stream);
00409 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00410 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00411 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag);
00412 static void update_messages_by_imapuser(const char *user, unsigned long number);
00413 static int vm_delete(char *file);
00414
00415 static int imap_remove_file (char *dir, int msgnum);
00416 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00417 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00418 static void check_quota(struct vm_state *vms, char *mailbox);
00419 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00420 struct vmstate {
00421 struct vm_state *vms;
00422 AST_LIST_ENTRY(vmstate) list;
00423 };
00424
00425 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00426
00427 #endif
00428
00429 #define SMDI_MWI_WAIT_TIMEOUT 1000
00430
00431 #define COMMAND_TIMEOUT 5000
00432
00433 #define VOICEMAIL_DIR_MODE 0777
00434 #define VOICEMAIL_FILE_MODE 0666
00435 #define CHUNKSIZE 65536
00436
00437 #define VOICEMAIL_CONFIG "voicemail.conf"
00438 #define ASTERISK_USERNAME "asterisk"
00439
00440
00441
00442
00443 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00444 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00445 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00446 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00447 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00448 #define VALID_DTMF "1234567890*#"
00449
00450
00451
00452 #define SENDMAIL "/usr/sbin/sendmail -t"
00453
00454 #define INTRO "vm-intro"
00455
00456 #define MAXMSG 100
00457 #define MAXMSGLIMIT 9999
00458
00459 #define MINPASSWORD 0
00460
00461 #define BASELINELEN 72
00462 #define BASEMAXINLINE 256
00463 #ifdef IMAP_STORAGE
00464 #define ENDL "\r\n"
00465 #else
00466 #define ENDL "\n"
00467 #endif
00468
00469 #define MAX_DATETIME_FORMAT 512
00470 #define MAX_NUM_CID_CONTEXTS 10
00471
00472 #define VM_REVIEW (1 << 0)
00473 #define VM_OPERATOR (1 << 1)
00474 #define VM_SAYCID (1 << 2)
00475 #define VM_SVMAIL (1 << 3)
00476 #define VM_ENVELOPE (1 << 4)
00477 #define VM_SAYDURATION (1 << 5)
00478 #define VM_SKIPAFTERCMD (1 << 6)
00479 #define VM_FORCENAME (1 << 7)
00480 #define VM_FORCEGREET (1 << 8)
00481 #define VM_PBXSKIP (1 << 9)
00482 #define VM_DIRECFORWARD (1 << 10)
00483 #define VM_ATTACH (1 << 11)
00484 #define VM_DELETE (1 << 12)
00485 #define VM_ALLOCED (1 << 13)
00486 #define VM_SEARCH (1 << 14)
00487 #define VM_TEMPGREETWARN (1 << 15)
00488 #define VM_MOVEHEARD (1 << 16)
00489 #define VM_MESSAGEWRAP (1 << 17)
00490 #define VM_FWDURGAUTO (1 << 18)
00491 #define ERROR_LOCK_PATH -100
00492 #define OPERATOR_EXIT 300
00493
00494
00495 enum vm_box {
00496 NEW_FOLDER,
00497 OLD_FOLDER,
00498 WORK_FOLDER,
00499 FAMILY_FOLDER,
00500 FRIENDS_FOLDER,
00501 GREETINGS_FOLDER
00502 };
00503
00504 enum vm_option_flags {
00505 OPT_SILENT = (1 << 0),
00506 OPT_BUSY_GREETING = (1 << 1),
00507 OPT_UNAVAIL_GREETING = (1 << 2),
00508 OPT_RECORDGAIN = (1 << 3),
00509 OPT_PREPEND_MAILBOX = (1 << 4),
00510 OPT_AUTOPLAY = (1 << 6),
00511 OPT_DTMFEXIT = (1 << 7),
00512 OPT_MESSAGE_Urgent = (1 << 8),
00513 OPT_MESSAGE_PRIORITY = (1 << 9)
00514 };
00515
00516 enum vm_option_args {
00517 OPT_ARG_RECORDGAIN = 0,
00518 OPT_ARG_PLAYFOLDER = 1,
00519 OPT_ARG_DTMFEXIT = 2,
00520
00521 OPT_ARG_ARRAY_SIZE = 3,
00522 };
00523
00524 enum vm_passwordlocation {
00525 OPT_PWLOC_VOICEMAILCONF = 0,
00526 OPT_PWLOC_SPOOLDIR = 1,
00527 OPT_PWLOC_USERSCONF = 2,
00528 };
00529
00530 AST_APP_OPTIONS(vm_app_options, {
00531 AST_APP_OPTION('s', OPT_SILENT),
00532 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00533 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00534 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00535 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00536 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00537 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00538 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00539 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00540 });
00541
00542 static int load_config(int reload);
00543 #ifdef TEST_FRAMEWORK
00544 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00545 #endif
00546 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 struct baseio {
00632 int iocp;
00633 int iolen;
00634 int linelength;
00635 int ateof;
00636 unsigned char iobuf[BASEMAXINLINE];
00637 };
00638
00639
00640
00641 struct ast_vm_user {
00642 char context[AST_MAX_CONTEXT];
00643 char mailbox[AST_MAX_EXTENSION];
00644 char password[80];
00645 char fullname[80];
00646 char email[80];
00647 char *emailsubject;
00648 char *emailbody;
00649 char pager[80];
00650 char serveremail[80];
00651 char mailcmd[160];
00652 char language[MAX_LANGUAGE];
00653 char zonetag[80];
00654 char locale[20];
00655 char callback[80];
00656 char dialout[80];
00657 char uniqueid[80];
00658 char exit[80];
00659 char attachfmt[20];
00660 unsigned int flags;
00661 int saydurationm;
00662 int minsecs;
00663 int maxmsg;
00664 int maxdeletedmsg;
00665 int maxsecs;
00666 int passwordlocation;
00667 #ifdef IMAP_STORAGE
00668 char imapuser[80];
00669 char imappassword[80];
00670 char imapfolder[64];
00671 char imapvmshareid[80];
00672 int imapversion;
00673 #endif
00674 double volgain;
00675 AST_LIST_ENTRY(ast_vm_user) list;
00676 };
00677
00678
00679 struct vm_zone {
00680 AST_LIST_ENTRY(vm_zone) list;
00681 char name[80];
00682 char timezone[80];
00683 char msg_format[512];
00684 };
00685
00686 #define VMSTATE_MAX_MSG_ARRAY 256
00687
00688
00689 struct vm_state {
00690 char curbox[80];
00691 char username[80];
00692 char context[80];
00693 char curdir[PATH_MAX];
00694 char vmbox[PATH_MAX];
00695 char fn[PATH_MAX];
00696 char intro[PATH_MAX];
00697 int *deleted;
00698 int *heard;
00699 int dh_arraysize;
00700 int curmsg;
00701 int lastmsg;
00702 int newmessages;
00703 int oldmessages;
00704 int urgentmessages;
00705 int starting;
00706 int repeats;
00707 #ifdef IMAP_STORAGE
00708 ast_mutex_t lock;
00709 int updated;
00710 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00711 MAILSTREAM *mailstream;
00712 int vmArrayIndex;
00713 char imapuser[80];
00714 char imapfolder[64];
00715 int imapversion;
00716 int interactive;
00717 char introfn[PATH_MAX];
00718 unsigned int quota_limit;
00719 unsigned int quota_usage;
00720 struct vm_state *persist_vms;
00721 #endif
00722 };
00723
00724 #ifdef ODBC_STORAGE
00725 static char odbc_database[80];
00726 static char odbc_table[80];
00727 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00728 #define DISPOSE(a,b) remove_file(a,b)
00729 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00730 #define EXISTS(a,b,c,d) (message_exists(a,b))
00731 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00732 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00733 #define DELETE(a,b,c,d) (delete_file(a,b))
00734 #else
00735 #ifdef IMAP_STORAGE
00736 #define DISPOSE(a,b) (imap_remove_file(a,b))
00737 #define STORE(a,b,c,d,e,f,g,h,i,j) (imap_store_file(a,b,c,d,e,f,g,h,i,j))
00738 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00739 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00740 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00741 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00742 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00743 #else
00744 #define RETRIEVE(a,b,c,d)
00745 #define DISPOSE(a,b)
00746 #define STORE(a,b,c,d,e,f,g,h,i,j)
00747 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00748 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00749 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00750 #define DELETE(a,b,c,d) (vm_delete(c))
00751 #endif
00752 #endif
00753
00754 static char VM_SPOOL_DIR[PATH_MAX];
00755
00756 static char ext_pass_cmd[128];
00757 static char ext_pass_check_cmd[128];
00758
00759 static int my_umask;
00760
00761 #define PWDCHANGE_INTERNAL (1 << 1)
00762 #define PWDCHANGE_EXTERNAL (1 << 2)
00763 static int pwdchange = PWDCHANGE_INTERNAL;
00764
00765 #ifdef ODBC_STORAGE
00766 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00767 #else
00768 # ifdef IMAP_STORAGE
00769 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00770 # else
00771 # define tdesc "Comedian Mail (Voicemail System)"
00772 # endif
00773 #endif
00774
00775 static char userscontext[AST_MAX_EXTENSION] = "default";
00776
00777 static char *addesc = "Comedian Mail";
00778
00779
00780 static char *app = "VoiceMail";
00781
00782
00783 static char *app2 = "VoiceMailMain";
00784
00785 static char *app3 = "MailboxExists";
00786 static char *app4 = "VMAuthenticate";
00787
00788 static char *sayname_app = "VMSayName";
00789
00790 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00791 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00792 static char zonetag[80];
00793 static char locale[20];
00794 static int maxsilence;
00795 static int maxmsg;
00796 static int maxdeletedmsg;
00797 static int silencethreshold = 128;
00798 static char serveremail[80];
00799 static char mailcmd[160];
00800 static char externnotify[160];
00801 static struct ast_smdi_interface *smdi_iface = NULL;
00802 static char vmfmts[80];
00803 static double volgain;
00804 static int vmminsecs;
00805 static int vmmaxsecs;
00806 static int maxgreet;
00807 static int skipms;
00808 static int maxlogins;
00809 static int minpassword;
00810 static int passwordlocation;
00811
00812
00813
00814 static unsigned int poll_mailboxes;
00815
00816
00817 static unsigned int poll_freq;
00818
00819 #define DEFAULT_POLL_FREQ 30
00820
00821 AST_MUTEX_DEFINE_STATIC(poll_lock);
00822 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00823 static pthread_t poll_thread = AST_PTHREADT_NULL;
00824 static unsigned char poll_thread_run;
00825
00826
00827 static struct ast_event_sub *mwi_sub_sub;
00828
00829 static struct ast_event_sub *mwi_unsub_sub;
00830
00831
00832
00833
00834
00835
00836
00837
00838 struct mwi_sub {
00839 AST_RWLIST_ENTRY(mwi_sub) entry;
00840 int old_urgent;
00841 int old_new;
00842 int old_old;
00843 uint32_t uniqueid;
00844 char mailbox[1];
00845 };
00846
00847 struct mwi_sub_task {
00848 const char *mailbox;
00849 const char *context;
00850 uint32_t uniqueid;
00851 };
00852
00853 static struct ast_taskprocessor *mwi_subscription_tps;
00854
00855 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00856
00857
00858 static char listen_control_forward_key[12];
00859 static char listen_control_reverse_key[12];
00860 static char listen_control_pause_key[12];
00861 static char listen_control_restart_key[12];
00862 static char listen_control_stop_key[12];
00863
00864
00865 static char vm_password[80] = "vm-password";
00866 static char vm_newpassword[80] = "vm-newpassword";
00867 static char vm_passchanged[80] = "vm-passchanged";
00868 static char vm_reenterpassword[80] = "vm-reenterpassword";
00869 static char vm_mismatch[80] = "vm-mismatch";
00870 static char vm_invalid_password[80] = "vm-invalid-password";
00871 static char vm_pls_try_again[80] = "vm-pls-try-again";
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883 static char vm_prepend_timeout[80] = "vm-then-pound";
00884
00885 static struct ast_flags globalflags = {0};
00886
00887 static int saydurationminfo;
00888
00889 static char dialcontext[AST_MAX_CONTEXT] = "";
00890 static char callcontext[AST_MAX_CONTEXT] = "";
00891 static char exitcontext[AST_MAX_CONTEXT] = "";
00892
00893 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00894
00895
00896 static char *emailbody = NULL;
00897 static char *emailsubject = NULL;
00898 static char *pagerbody = NULL;
00899 static char *pagersubject = NULL;
00900 static char fromstring[100];
00901 static char pagerfromstring[100];
00902 static char charset[32] = "ISO-8859-1";
00903
00904 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00905 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00906 static int adsiver = 1;
00907 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00908 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00909
00910
00911 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00912 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain);
00913 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00914 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00915 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00916 signed char record_gain, struct vm_state *vms, char *flag);
00917 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00918 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00919 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag);
00920 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag);
00921 static void apply_options(struct ast_vm_user *vmu, const char *options);
00922 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum);
00923 static int is_valid_dtmf(const char *key);
00924 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00925 static int write_password_to_file(const char *secretfn, const char *password);
00926 static const char *substitute_escapes(const char *value);
00927 static void free_user(struct ast_vm_user *vmu);
00928
00929 struct ao2_container *inprocess_container;
00930
00931 struct inprocess {
00932 int count;
00933 char *context;
00934 char mailbox[0];
00935 };
00936
00937 static int inprocess_hash_fn(const void *obj, const int flags)
00938 {
00939 const struct inprocess *i = obj;
00940 return atoi(i->mailbox);
00941 }
00942
00943 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00944 {
00945 struct inprocess *i = obj, *j = arg;
00946 if (strcmp(i->mailbox, j->mailbox)) {
00947 return 0;
00948 }
00949 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00950 }
00951
00952 static int inprocess_count(const char *context, const char *mailbox, int delta)
00953 {
00954 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00955 arg->context = arg->mailbox + strlen(mailbox) + 1;
00956 strcpy(arg->mailbox, mailbox);
00957 strcpy(arg->context, context);
00958 ao2_lock(inprocess_container);
00959 if ((i = ao2_find(inprocess_container, arg, 0))) {
00960 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00961 ao2_unlock(inprocess_container);
00962 ao2_ref(i, -1);
00963 return ret;
00964 }
00965 if (delta < 0) {
00966 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00967 }
00968 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00969 ao2_unlock(inprocess_container);
00970 return 0;
00971 }
00972 i->context = i->mailbox + strlen(mailbox) + 1;
00973 strcpy(i->mailbox, mailbox);
00974 strcpy(i->context, context);
00975 i->count = delta;
00976 ao2_link(inprocess_container, i);
00977 ao2_unlock(inprocess_container);
00978 ao2_ref(i, -1);
00979 return 0;
00980 }
00981
00982 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00983 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00984 #endif
00985
00986
00987
00988
00989
00990
00991
00992 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00993 {
00994 char *bufptr = buf;
00995 for (; *input; input++) {
00996 if (*input < 32) {
00997 continue;
00998 }
00999 *bufptr++ = *input;
01000 if (bufptr == buf + buflen - 1) {
01001 break;
01002 }
01003 }
01004 *bufptr = '\0';
01005 return buf;
01006 }
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022 static void populate_defaults(struct ast_vm_user *vmu)
01023 {
01024 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01025 vmu->passwordlocation = passwordlocation;
01026 if (saydurationminfo) {
01027 vmu->saydurationm = saydurationminfo;
01028 }
01029 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01030 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01031 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01032 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01033 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01034 if (vmminsecs) {
01035 vmu->minsecs = vmminsecs;
01036 }
01037 if (vmmaxsecs) {
01038 vmu->maxsecs = vmmaxsecs;
01039 }
01040 if (maxmsg) {
01041 vmu->maxmsg = maxmsg;
01042 }
01043 if (maxdeletedmsg) {
01044 vmu->maxdeletedmsg = maxdeletedmsg;
01045 }
01046 vmu->volgain = volgain;
01047 ast_free(vmu->emailsubject);
01048 vmu->emailsubject = NULL;
01049 ast_free(vmu->emailbody);
01050 vmu->emailbody = NULL;
01051 #ifdef IMAP_STORAGE
01052 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01053 #endif
01054 }
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01065 {
01066 int x;
01067 if (!strcasecmp(var, "attach")) {
01068 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01069 } else if (!strcasecmp(var, "attachfmt")) {
01070 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01071 } else if (!strcasecmp(var, "serveremail")) {
01072 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01073 } else if (!strcasecmp(var, "emailbody")) {
01074 vmu->emailbody = ast_strdup(substitute_escapes(value));
01075 } else if (!strcasecmp(var, "emailsubject")) {
01076 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01077 } else if (!strcasecmp(var, "language")) {
01078 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01079 } else if (!strcasecmp(var, "tz")) {
01080 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01081 } else if (!strcasecmp(var, "locale")) {
01082 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01083 #ifdef IMAP_STORAGE
01084 } else if (!strcasecmp(var, "imapuser")) {
01085 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01086 vmu->imapversion = imapversion;
01087 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01088 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01089 vmu->imapversion = imapversion;
01090 } else if (!strcasecmp(var, "imapfolder")) {
01091 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01092 } else if (!strcasecmp(var, "imapvmshareid")) {
01093 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01094 vmu->imapversion = imapversion;
01095 #endif
01096 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01097 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01098 } else if (!strcasecmp(var, "saycid")){
01099 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01100 } else if (!strcasecmp(var, "sendvoicemail")){
01101 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01102 } else if (!strcasecmp(var, "review")){
01103 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01104 } else if (!strcasecmp(var, "tempgreetwarn")){
01105 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01106 } else if (!strcasecmp(var, "messagewrap")){
01107 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01108 } else if (!strcasecmp(var, "operator")) {
01109 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01110 } else if (!strcasecmp(var, "envelope")){
01111 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01112 } else if (!strcasecmp(var, "moveheard")){
01113 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01114 } else if (!strcasecmp(var, "sayduration")){
01115 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01116 } else if (!strcasecmp(var, "saydurationm")){
01117 if (sscanf(value, "%30d", &x) == 1) {
01118 vmu->saydurationm = x;
01119 } else {
01120 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01121 }
01122 } else if (!strcasecmp(var, "forcename")){
01123 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01124 } else if (!strcasecmp(var, "forcegreetings")){
01125 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01126 } else if (!strcasecmp(var, "callback")) {
01127 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01128 } else if (!strcasecmp(var, "dialout")) {
01129 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01130 } else if (!strcasecmp(var, "exitcontext")) {
01131 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01132 } else if (!strcasecmp(var, "minsecs")) {
01133 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01134 vmu->minsecs = x;
01135 } else {
01136 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01137 vmu->minsecs = vmminsecs;
01138 }
01139 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01140 vmu->maxsecs = atoi(value);
01141 if (vmu->maxsecs <= 0) {
01142 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01143 vmu->maxsecs = vmmaxsecs;
01144 } else {
01145 vmu->maxsecs = atoi(value);
01146 }
01147 if (!strcasecmp(var, "maxmessage"))
01148 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01149 } else if (!strcasecmp(var, "maxmsg")) {
01150 vmu->maxmsg = atoi(value);
01151
01152 if (vmu->maxmsg < 0) {
01153 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01154 vmu->maxmsg = MAXMSG;
01155 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01156 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01157 vmu->maxmsg = MAXMSGLIMIT;
01158 }
01159 } else if (!strcasecmp(var, "nextaftercmd")) {
01160 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01161 } else if (!strcasecmp(var, "backupdeleted")) {
01162 if (sscanf(value, "%30d", &x) == 1)
01163 vmu->maxdeletedmsg = x;
01164 else if (ast_true(value))
01165 vmu->maxdeletedmsg = MAXMSG;
01166 else
01167 vmu->maxdeletedmsg = 0;
01168
01169 if (vmu->maxdeletedmsg < 0) {
01170 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01171 vmu->maxdeletedmsg = MAXMSG;
01172 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01173 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01174 vmu->maxdeletedmsg = MAXMSGLIMIT;
01175 }
01176 } else if (!strcasecmp(var, "volgain")) {
01177 sscanf(value, "%30lf", &vmu->volgain);
01178 } else if (!strcasecmp(var, "passwordlocation")) {
01179 if (!strcasecmp(value, "spooldir")) {
01180 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01181 } else {
01182 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01183 }
01184 } else if (!strcasecmp(var, "options")) {
01185 apply_options(vmu, value);
01186 }
01187 }
01188
01189 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01190 {
01191 int fds[2], pid = 0;
01192
01193 memset(buf, 0, len);
01194
01195 if (pipe(fds)) {
01196 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01197 } else {
01198
01199 pid = ast_safe_fork(0);
01200
01201 if (pid < 0) {
01202
01203 close(fds[0]);
01204 close(fds[1]);
01205 snprintf(buf, len, "FAILURE: Fork failed");
01206 } else if (pid) {
01207
01208 close(fds[1]);
01209 if (read(fds[0], buf, len) < 0) {
01210 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01211 }
01212 close(fds[0]);
01213 } else {
01214
01215 AST_DECLARE_APP_ARGS(arg,
01216 AST_APP_ARG(v)[20];
01217 );
01218 char *mycmd = ast_strdupa(command);
01219
01220 close(fds[0]);
01221 dup2(fds[1], STDOUT_FILENO);
01222 close(fds[1]);
01223 ast_close_fds_above_n(STDOUT_FILENO);
01224
01225 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01226
01227 execv(arg.v[0], arg.v);
01228 printf("FAILURE: %s", strerror(errno));
01229 _exit(0);
01230 }
01231 }
01232 return buf;
01233 }
01234
01235
01236
01237
01238
01239
01240
01241
01242 static int check_password(struct ast_vm_user *vmu, char *password)
01243 {
01244
01245 if (strlen(password) < minpassword)
01246 return 1;
01247
01248 if (!ast_strlen_zero(password) && password[0] == '*')
01249 return 1;
01250 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01251 char cmd[255], buf[255];
01252
01253 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01254
01255 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01256 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01257 ast_debug(5, "Result: %s\n", buf);
01258 if (!strncasecmp(buf, "VALID", 5)) {
01259 ast_debug(3, "Passed password check: '%s'\n", buf);
01260 return 0;
01261 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01262 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01263 return 0;
01264 } else {
01265 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01266 return 1;
01267 }
01268 }
01269 }
01270 return 0;
01271 }
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01284 {
01285 int res = -1;
01286 if (!strcmp(vmu->password, password)) {
01287
01288 return 0;
01289 }
01290
01291 if (strlen(password) > 10) {
01292 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01293 }
01294 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01295 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01296 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01297 res = 0;
01298 }
01299 return res;
01300 }
01301
01302
01303
01304
01305 static void apply_options(struct ast_vm_user *vmu, const char *options)
01306 {
01307 char *stringp;
01308 char *s;
01309 char *var, *value;
01310 stringp = ast_strdupa(options);
01311 while ((s = strsep(&stringp, "|"))) {
01312 value = s;
01313 if ((var = strsep(&value, "=")) && value) {
01314 apply_option(vmu, var, value);
01315 }
01316 }
01317 }
01318
01319
01320
01321
01322
01323
01324 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01325 {
01326 for (; var; var = var->next) {
01327 if (!strcasecmp(var->name, "vmsecret")) {
01328 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01329 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01330 if (ast_strlen_zero(retval->password)) {
01331 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01332 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01333 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01334 } else {
01335 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01336 }
01337 }
01338 } else if (!strcasecmp(var->name, "uniqueid")) {
01339 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01340 } else if (!strcasecmp(var->name, "pager")) {
01341 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01342 } else if (!strcasecmp(var->name, "email")) {
01343 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01344 } else if (!strcasecmp(var->name, "fullname")) {
01345 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01346 } else if (!strcasecmp(var->name, "context")) {
01347 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01348 } else if (!strcasecmp(var->name, "emailsubject")) {
01349 ast_free(retval->emailsubject);
01350 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01351 } else if (!strcasecmp(var->name, "emailbody")) {
01352 ast_free(retval->emailbody);
01353 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01354 #ifdef IMAP_STORAGE
01355 } else if (!strcasecmp(var->name, "imapuser")) {
01356 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01357 retval->imapversion = imapversion;
01358 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01359 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01360 retval->imapversion = imapversion;
01361 } else if (!strcasecmp(var->name, "imapfolder")) {
01362 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01363 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01364 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01365 retval->imapversion = imapversion;
01366 #endif
01367 } else
01368 apply_option(retval, var->name, var->value);
01369 }
01370 }
01371
01372
01373
01374
01375
01376
01377
01378
01379 static int is_valid_dtmf(const char *key)
01380 {
01381 int i;
01382 char *local_key = ast_strdupa(key);
01383
01384 for (i = 0; i < strlen(key); ++i) {
01385 if (!strchr(VALID_DTMF, *local_key)) {
01386 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01387 return 0;
01388 }
01389 local_key++;
01390 }
01391 return 1;
01392 }
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01405 {
01406 struct ast_variable *var;
01407 struct ast_vm_user *retval;
01408
01409 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01410 if (!ivm)
01411 ast_set_flag(retval, VM_ALLOCED);
01412 else
01413 memset(retval, 0, sizeof(*retval));
01414 if (mailbox)
01415 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01416 populate_defaults(retval);
01417 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01418 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01419 else
01420 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01421 if (var) {
01422 apply_options_full(retval, var);
01423 ast_variables_destroy(var);
01424 } else {
01425 if (!ivm)
01426 free_user(retval);
01427 retval = NULL;
01428 }
01429 }
01430 return retval;
01431 }
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01442 {
01443
01444 struct ast_vm_user *vmu = NULL, *cur;
01445 AST_LIST_LOCK(&users);
01446
01447 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01448 context = "default";
01449
01450 AST_LIST_TRAVERSE(&users, cur, list) {
01451 #ifdef IMAP_STORAGE
01452 if (cur->imapversion != imapversion) {
01453 continue;
01454 }
01455 #endif
01456 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01457 break;
01458 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01459 break;
01460 }
01461 if (cur) {
01462
01463 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01464 *vmu = *cur;
01465 if (!ivm) {
01466 vmu->emailbody = ast_strdup(cur->emailbody);
01467 vmu->emailsubject = ast_strdup(cur->emailsubject);
01468 }
01469 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01470 AST_LIST_NEXT(vmu, list) = NULL;
01471 }
01472 } else
01473 vmu = find_user_realtime(ivm, context, mailbox);
01474 AST_LIST_UNLOCK(&users);
01475 return vmu;
01476 }
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01489 {
01490
01491 struct ast_vm_user *cur;
01492 int res = -1;
01493 AST_LIST_LOCK(&users);
01494 AST_LIST_TRAVERSE(&users, cur, list) {
01495 if ((!context || !strcasecmp(context, cur->context)) &&
01496 (!strcasecmp(mailbox, cur->mailbox)))
01497 break;
01498 }
01499 if (cur) {
01500 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01501 res = 0;
01502 }
01503 AST_LIST_UNLOCK(&users);
01504 return res;
01505 }
01506
01507
01508
01509
01510
01511
01512
01513
01514 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01515 {
01516 struct ast_config *cfg = NULL;
01517 struct ast_variable *var = NULL;
01518 struct ast_category *cat = NULL;
01519 char *category = NULL, *value = NULL, *new = NULL;
01520 const char *tmp = NULL;
01521 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01522 char secretfn[PATH_MAX] = "";
01523 int found = 0;
01524
01525 if (!change_password_realtime(vmu, newpassword))
01526 return;
01527
01528
01529 switch (vmu->passwordlocation) {
01530 case OPT_PWLOC_SPOOLDIR:
01531 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01532 if (write_password_to_file(secretfn, newpassword) == 0) {
01533 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01534 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01535 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01536 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01537 break;
01538 } else {
01539 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01540 }
01541
01542 case OPT_PWLOC_VOICEMAILCONF:
01543 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01544 while ((category = ast_category_browse(cfg, category))) {
01545 if (!strcasecmp(category, vmu->context)) {
01546 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01547 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01548 break;
01549 }
01550 value = strstr(tmp, ",");
01551 if (!value) {
01552 new = alloca(strlen(newpassword)+1);
01553 sprintf(new, "%s", newpassword);
01554 } else {
01555 new = alloca((strlen(value) + strlen(newpassword) + 1));
01556 sprintf(new, "%s%s", newpassword, value);
01557 }
01558 if (!(cat = ast_category_get(cfg, category))) {
01559 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01560 break;
01561 }
01562 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01563 found = 1;
01564 }
01565 }
01566
01567 if (found) {
01568 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01569 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01570 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01571 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01572 break;
01573 }
01574 }
01575
01576 case OPT_PWLOC_USERSCONF:
01577
01578
01579 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01580 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01581 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01582 ast_debug(4, "users.conf: %s\n", category);
01583 if (!strcasecmp(category, vmu->mailbox)) {
01584 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01585 ast_debug(3, "looks like we need to make vmsecret!\n");
01586 var = ast_variable_new("vmsecret", newpassword, "");
01587 } else {
01588 var = NULL;
01589 }
01590 new = alloca(strlen(newpassword) + 1);
01591 sprintf(new, "%s", newpassword);
01592 if (!(cat = ast_category_get(cfg, category))) {
01593 ast_debug(4, "failed to get category!\n");
01594 ast_free(var);
01595 break;
01596 }
01597 if (!var) {
01598 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01599 } else {
01600 ast_variable_append(cat, var);
01601 }
01602 found = 1;
01603 break;
01604 }
01605 }
01606
01607 if (found) {
01608 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01609 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01610 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01611 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01612 }
01613 }
01614 }
01615 }
01616
01617 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01618 {
01619 char buf[255];
01620 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01621 ast_debug(1, "External password: %s\n",buf);
01622 if (!ast_safe_system(buf)) {
01623 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01624 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01625
01626 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01627 }
01628 }
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01644 {
01645 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01646 }
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660 static int make_file(char *dest, const int len, const char *dir, const int num)
01661 {
01662 return snprintf(dest, len, "%s/msg%04d", dir, num);
01663 }
01664
01665
01666 static FILE *vm_mkftemp(char *template)
01667 {
01668 FILE *p = NULL;
01669 int pfd = mkstemp(template);
01670 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01671 if (pfd > -1) {
01672 p = fdopen(pfd, "w+");
01673 if (!p) {
01674 close(pfd);
01675 pfd = -1;
01676 }
01677 }
01678 return p;
01679 }
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01690 {
01691 mode_t mode = VOICEMAIL_DIR_MODE;
01692 int res;
01693
01694 make_dir(dest, len, context, ext, folder);
01695 if ((res = ast_mkdir(dest, mode))) {
01696 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01697 return -1;
01698 }
01699 return 0;
01700 }
01701
01702 static const char * const mailbox_folders[] = {
01703 #ifdef IMAP_STORAGE
01704 imapfolder,
01705 #else
01706 "INBOX",
01707 #endif
01708 "Old",
01709 "Work",
01710 "Family",
01711 "Friends",
01712 "Cust1",
01713 "Cust2",
01714 "Cust3",
01715 "Cust4",
01716 "Cust5",
01717 "Deleted",
01718 "Urgent",
01719 };
01720
01721 static const char *mbox(struct ast_vm_user *vmu, int id)
01722 {
01723 #ifdef IMAP_STORAGE
01724 if (vmu && id == 0) {
01725 return vmu->imapfolder;
01726 }
01727 #endif
01728 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01729 }
01730
01731 static int get_folder_by_name(const char *name)
01732 {
01733 size_t i;
01734
01735 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01736 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01737 return i;
01738 }
01739 }
01740
01741 return -1;
01742 }
01743
01744 static void free_user(struct ast_vm_user *vmu)
01745 {
01746 if (ast_test_flag(vmu, VM_ALLOCED)) {
01747
01748 ast_free(vmu->emailbody);
01749 vmu->emailbody = NULL;
01750
01751 ast_free(vmu->emailsubject);
01752 vmu->emailsubject = NULL;
01753
01754 ast_free(vmu);
01755 }
01756 }
01757
01758 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01759
01760 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01761
01762
01763 if (vms->deleted) {
01764 ast_free(vms->deleted);
01765 vms->deleted = NULL;
01766 }
01767 if (vms->heard) {
01768 ast_free(vms->heard);
01769 vms->heard = NULL;
01770 }
01771 vms->dh_arraysize = 0;
01772
01773 if (arraysize > 0) {
01774 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01775 return -1;
01776 }
01777 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01778 ast_free(vms->deleted);
01779 vms->deleted = NULL;
01780 return -1;
01781 }
01782 vms->dh_arraysize = arraysize;
01783 }
01784
01785 return 0;
01786 }
01787
01788
01789
01790 #ifdef IMAP_STORAGE
01791 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01792 {
01793 char arg[10];
01794 struct vm_state *vms;
01795 unsigned long messageNum;
01796
01797
01798 if (msgnum < 0 && !imapgreetings) {
01799 ast_filedelete(file, NULL);
01800 return;
01801 }
01802
01803 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01804 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);
01805 return;
01806 }
01807
01808
01809
01810 messageNum = vms->msgArray[msgnum];
01811 if (messageNum == 0) {
01812 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01813 return;
01814 }
01815 if (option_debug > 2)
01816 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01817
01818 snprintf (arg, sizeof(arg), "%lu", messageNum);
01819 ast_mutex_lock(&vms->lock);
01820 mail_setflag (vms->mailstream, arg, "\\DELETED");
01821 mail_expunge(vms->mailstream);
01822 ast_mutex_unlock(&vms->lock);
01823 }
01824
01825 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01826 {
01827 struct vm_state *vms_p;
01828 char *file, *filename;
01829 char *attachment;
01830 int i;
01831 BODY *body;
01832
01833
01834
01835
01836 if (msgnum > -1 || !imapgreetings) {
01837 return 0;
01838 } else {
01839 file = strrchr(ast_strdupa(dir), '/');
01840 if (file)
01841 *file++ = '\0';
01842 else {
01843 ast_debug (1, "Failed to procure file name from directory passed.\n");
01844 return -1;
01845 }
01846 }
01847
01848
01849 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01850 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01851
01852
01853
01854
01855 if (!(vms_p = create_vm_state_from_user(vmu))) {
01856 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01857 return -1;
01858 }
01859 }
01860
01861
01862 *vms_p->introfn = '\0';
01863
01864 ast_mutex_lock(&vms_p->lock);
01865 init_mailstream(vms_p, GREETINGS_FOLDER);
01866 if (!vms_p->mailstream) {
01867 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01868 ast_mutex_unlock(&vms_p->lock);
01869 return -1;
01870 }
01871
01872
01873 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01874 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01875
01876 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01877 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01878 } else {
01879 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01880 ast_mutex_unlock(&vms_p->lock);
01881 return -1;
01882 }
01883 filename = strsep(&attachment, ".");
01884 if (!strcmp(filename, file)) {
01885 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01886 vms_p->msgArray[vms_p->curmsg] = i + 1;
01887 save_body(body, vms_p, "2", attachment, 0);
01888 ast_mutex_unlock(&vms_p->lock);
01889 return 0;
01890 }
01891 }
01892 ast_mutex_unlock(&vms_p->lock);
01893
01894 return -1;
01895 }
01896
01897 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01898 {
01899 BODY *body;
01900 char *header_content;
01901 char *attachedfilefmt;
01902 char buf[80];
01903 struct vm_state *vms;
01904 char text_file[PATH_MAX];
01905 FILE *text_file_ptr;
01906 int res = 0;
01907 struct ast_vm_user *vmu;
01908
01909 if (!(vmu = find_user(NULL, context, mailbox))) {
01910 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01911 return -1;
01912 }
01913
01914 if (msgnum < 0) {
01915 if (imapgreetings) {
01916 res = imap_retrieve_greeting(dir, msgnum, vmu);
01917 goto exit;
01918 } else {
01919 res = 0;
01920 goto exit;
01921 }
01922 }
01923
01924
01925
01926
01927 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01928
01929
01930
01931
01932
01933
01934
01935 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01936 res = -1;
01937 goto exit;
01938 }
01939
01940 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01941 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01942
01943
01944 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01945 res = 0;
01946 goto exit;
01947 }
01948
01949 if (option_debug > 2)
01950 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01951 if (vms->msgArray[msgnum] == 0) {
01952 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01953 res = -1;
01954 goto exit;
01955 }
01956
01957
01958 ast_mutex_lock(&vms->lock);
01959 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01960 ast_mutex_unlock(&vms->lock);
01961
01962 if (ast_strlen_zero(header_content)) {
01963 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01964 res = -1;
01965 goto exit;
01966 }
01967
01968 ast_mutex_lock(&vms->lock);
01969 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01970 ast_mutex_unlock(&vms->lock);
01971
01972
01973 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01974 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01975 } else {
01976 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01977 res = -1;
01978 goto exit;
01979 }
01980
01981
01982
01983 strsep(&attachedfilefmt, ".");
01984 if (!attachedfilefmt) {
01985 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01986 res = -1;
01987 goto exit;
01988 }
01989
01990 save_body(body, vms, "2", attachedfilefmt, 0);
01991 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01992 *vms->introfn = '\0';
01993 }
01994
01995
01996 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01997
01998 if (!(text_file_ptr = fopen(text_file, "w"))) {
01999 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
02000 }
02001
02002 fprintf(text_file_ptr, "%s\n", "[message]");
02003
02004 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02005 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02006 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02007 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02008 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02009 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02010 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02011 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02012 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02013 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02014 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02015 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02016 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02017 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02018 fclose(text_file_ptr);
02019
02020 exit:
02021 free_user(vmu);
02022 return res;
02023 }
02024
02025 static int folder_int(const char *folder)
02026 {
02027
02028 if (!folder) {
02029 return 0;
02030 }
02031 if (!strcasecmp(folder, imapfolder)) {
02032 return 0;
02033 } else if (!strcasecmp(folder, "Old")) {
02034 return 1;
02035 } else if (!strcasecmp(folder, "Work")) {
02036 return 2;
02037 } else if (!strcasecmp(folder, "Family")) {
02038 return 3;
02039 } else if (!strcasecmp(folder, "Friends")) {
02040 return 4;
02041 } else if (!strcasecmp(folder, "Cust1")) {
02042 return 5;
02043 } else if (!strcasecmp(folder, "Cust2")) {
02044 return 6;
02045 } else if (!strcasecmp(folder, "Cust3")) {
02046 return 7;
02047 } else if (!strcasecmp(folder, "Cust4")) {
02048 return 8;
02049 } else if (!strcasecmp(folder, "Cust5")) {
02050 return 9;
02051 } else if (!strcasecmp(folder, "Urgent")) {
02052 return 11;
02053 } else {
02054 return 0;
02055 }
02056 }
02057
02058 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02059 {
02060 SEARCHPGM *pgm;
02061 SEARCHHEADER *hdr;
02062
02063 struct ast_vm_user *vmu, vmus;
02064 struct vm_state *vms_p;
02065 int ret = 0;
02066 int fold = folder_int(folder);
02067 int urgent = 0;
02068
02069
02070 if (fold == 11) {
02071 fold = NEW_FOLDER;
02072 urgent = 1;
02073 }
02074
02075 if (ast_strlen_zero(mailbox))
02076 return 0;
02077
02078
02079 vmu = find_user(&vmus, context, mailbox);
02080 if (!vmu) {
02081 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02082 return -1;
02083 } else {
02084
02085 if (vmu->imapuser[0] == '\0') {
02086 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02087 return -1;
02088 }
02089 }
02090
02091
02092 if (vmu->imapuser[0] == '\0') {
02093 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02094 free_user(vmu);
02095 return -1;
02096 }
02097
02098
02099 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02100 if (!vms_p) {
02101 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02102 }
02103 if (vms_p) {
02104 ast_debug(3, "Returning before search - user is logged in\n");
02105 if (fold == 0) {
02106 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02107 }
02108 if (fold == 1) {
02109 return vms_p->oldmessages;
02110 }
02111 }
02112
02113
02114 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02115 if (!vms_p) {
02116 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02117 }
02118
02119 if (!vms_p) {
02120 vms_p = create_vm_state_from_user(vmu);
02121 }
02122 ret = init_mailstream(vms_p, fold);
02123 if (!vms_p->mailstream) {
02124 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02125 return -1;
02126 }
02127 if (ret == 0) {
02128 ast_mutex_lock(&vms_p->lock);
02129 pgm = mail_newsearchpgm ();
02130 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02131 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02132 pgm->header = hdr;
02133 if (fold != OLD_FOLDER) {
02134 pgm->unseen = 1;
02135 pgm->seen = 0;
02136 }
02137
02138
02139
02140 else {
02141 pgm->unseen = 0;
02142 pgm->seen = 1;
02143 }
02144
02145 if (fold == NEW_FOLDER) {
02146 if (urgent) {
02147 pgm->flagged = 1;
02148 pgm->unflagged = 0;
02149 } else {
02150 pgm->flagged = 0;
02151 pgm->unflagged = 1;
02152 }
02153 }
02154 pgm->undeleted = 1;
02155 pgm->deleted = 0;
02156
02157 vms_p->vmArrayIndex = 0;
02158 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02159 if (fold == 0 && urgent == 0)
02160 vms_p->newmessages = vms_p->vmArrayIndex;
02161 if (fold == 1)
02162 vms_p->oldmessages = vms_p->vmArrayIndex;
02163 if (fold == 0 && urgent == 1)
02164 vms_p->urgentmessages = vms_p->vmArrayIndex;
02165
02166 mail_free_searchpgm(&pgm);
02167 ast_mutex_unlock(&vms_p->lock);
02168 vms_p->updated = 0;
02169 return vms_p->vmArrayIndex;
02170 } else {
02171 ast_mutex_lock(&vms_p->lock);
02172 mail_ping(vms_p->mailstream);
02173 ast_mutex_unlock(&vms_p->lock);
02174 }
02175 return 0;
02176 }
02177
02178 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02179 {
02180
02181 check_quota(vms, vmu->imapfolder);
02182 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02183 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02184 ast_play_and_wait(chan, "vm-mailboxfull");
02185 return -1;
02186 }
02187
02188
02189 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));
02190 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02191 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02192 ast_play_and_wait(chan, "vm-mailboxfull");
02193 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02194 return -1;
02195 }
02196
02197 return 0;
02198 }
02199
02200
02201
02202
02203
02204
02205
02206
02207
02208
02209 static int messagecount(const char *context, const char *mailbox, const char *folder)
02210 {
02211 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02212 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02213 } else {
02214 return __messagecount(context, mailbox, folder);
02215 }
02216 }
02217
02218 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)
02219 {
02220 char *myserveremail = serveremail;
02221 char fn[PATH_MAX];
02222 char introfn[PATH_MAX];
02223 char mailbox[256];
02224 char *stringp;
02225 FILE *p = NULL;
02226 char tmp[80] = "/tmp/astmail-XXXXXX";
02227 long len;
02228 void *buf;
02229 int tempcopy = 0;
02230 STRING str;
02231 int ret;
02232 char *imap_flags = NIL;
02233 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02234 int box = NEW_FOLDER;
02235
02236
02237 if (msgnum < 0) {
02238 if(!imapgreetings) {
02239 return 0;
02240 } else {
02241 box = GREETINGS_FOLDER;
02242 }
02243 }
02244
02245 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02246 return -1;
02247 }
02248
02249
02250 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02251 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02252 imap_flags = "\\FLAGGED";
02253 }
02254
02255
02256 fmt = ast_strdupa(fmt);
02257 stringp = fmt;
02258 strsep(&stringp, "|");
02259
02260 if (!ast_strlen_zero(vmu->serveremail))
02261 myserveremail = vmu->serveremail;
02262
02263 if (msgnum > -1)
02264 make_file(fn, sizeof(fn), dir, msgnum);
02265 else
02266 ast_copy_string (fn, dir, sizeof(fn));
02267
02268 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02269 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02270 *introfn = '\0';
02271 }
02272
02273 if (ast_strlen_zero(vmu->email)) {
02274
02275
02276
02277
02278
02279 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02280 tempcopy = 1;
02281 }
02282
02283 if (!strcmp(fmt, "wav49"))
02284 fmt = "WAV";
02285 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02286
02287
02288
02289 if (!(p = vm_mkftemp(tmp))) {
02290 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02291 if (tempcopy)
02292 *(vmu->email) = '\0';
02293 return -1;
02294 }
02295
02296 if (msgnum < 0 && imapgreetings) {
02297 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02298 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02299 return -1;
02300 }
02301 imap_delete_old_greeting(fn, vms);
02302 }
02303
02304 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02305 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02306 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02307 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02308
02309 len = ftell(p);
02310 rewind(p);
02311 if (!(buf = ast_malloc(len + 1))) {
02312 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02313 fclose(p);
02314 if (tempcopy)
02315 *(vmu->email) = '\0';
02316 return -1;
02317 }
02318 if (fread(buf, len, 1, p) < len) {
02319 if (ferror(p)) {
02320 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02321 return -1;
02322 }
02323 }
02324 ((char *) buf)[len] = '\0';
02325 INIT(&str, mail_string, buf, len);
02326 ret = init_mailstream(vms, box);
02327 if (ret == 0) {
02328 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02329 ast_mutex_lock(&vms->lock);
02330 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02331 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02332 ast_mutex_unlock(&vms->lock);
02333 fclose(p);
02334 unlink(tmp);
02335 ast_free(buf);
02336 } else {
02337 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02338 fclose(p);
02339 unlink(tmp);
02340 ast_free(buf);
02341 return -1;
02342 }
02343 ast_debug(3, "%s stored\n", fn);
02344
02345 if (tempcopy)
02346 *(vmu->email) = '\0';
02347 inprocess_count(vmu->mailbox, vmu->context, -1);
02348 return 0;
02349
02350 }
02351
02352
02353
02354
02355
02356
02357
02358
02359
02360
02361
02362
02363
02364
02365 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02366 {
02367 char tmp[PATH_MAX] = "";
02368 char *mailboxnc;
02369 char *context;
02370 char *mb;
02371 char *cur;
02372 if (newmsgs)
02373 *newmsgs = 0;
02374 if (oldmsgs)
02375 *oldmsgs = 0;
02376 if (urgentmsgs)
02377 *urgentmsgs = 0;
02378
02379 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02380
02381 if (ast_strlen_zero(mailbox_context))
02382 return 0;
02383
02384 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02385 context = strchr(tmp, '@');
02386 if (strchr(mailbox_context, ',')) {
02387 int tmpnew, tmpold, tmpurgent;
02388 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02389 mb = tmp;
02390 while ((cur = strsep(&mb, ", "))) {
02391 if (!ast_strlen_zero(cur)) {
02392 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02393 return -1;
02394 else {
02395 if (newmsgs)
02396 *newmsgs += tmpnew;
02397 if (oldmsgs)
02398 *oldmsgs += tmpold;
02399 if (urgentmsgs)
02400 *urgentmsgs += tmpurgent;
02401 }
02402 }
02403 }
02404 return 0;
02405 }
02406 if (context) {
02407 *context = '\0';
02408 mailboxnc = tmp;
02409 context++;
02410 } else {
02411 context = "default";
02412 mailboxnc = (char *) mailbox_context;
02413 }
02414
02415 if (newmsgs) {
02416 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02417 if (!vmu) {
02418 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02419 return -1;
02420 }
02421 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02422 return -1;
02423 }
02424 }
02425 if (oldmsgs) {
02426 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02427 return -1;
02428 }
02429 }
02430 if (urgentmsgs) {
02431 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02432 return -1;
02433 }
02434 }
02435 return 0;
02436 }
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448 static int has_voicemail(const char *mailbox, const char *folder)
02449 {
02450 char tmp[256], *tmp2, *box, *context;
02451 ast_copy_string(tmp, mailbox, sizeof(tmp));
02452 tmp2 = tmp;
02453 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02454 while ((box = strsep(&tmp2, ",&"))) {
02455 if (!ast_strlen_zero(box)) {
02456 if (has_voicemail(box, folder)) {
02457 return 1;
02458 }
02459 }
02460 }
02461 }
02462 if ((context = strchr(tmp, '@'))) {
02463 *context++ = '\0';
02464 } else {
02465 context = "default";
02466 }
02467 return __messagecount(context, tmp, folder) ? 1 : 0;
02468 }
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485 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)
02486 {
02487 struct vm_state *sendvms = NULL, *destvms = NULL;
02488 char messagestring[10];
02489 if (msgnum >= recip->maxmsg) {
02490 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02491 return -1;
02492 }
02493 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02494 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02495 return -1;
02496 }
02497 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02498 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02499 return -1;
02500 }
02501 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02502 ast_mutex_lock(&sendvms->lock);
02503 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02504 ast_mutex_unlock(&sendvms->lock);
02505 return 0;
02506 }
02507 ast_mutex_unlock(&sendvms->lock);
02508 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02509 return -1;
02510 }
02511
02512 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02513 {
02514 char tmp[256], *t = tmp;
02515 size_t left = sizeof(tmp);
02516
02517 if (box == OLD_FOLDER) {
02518 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02519 } else {
02520 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02521 }
02522
02523 if (box == NEW_FOLDER) {
02524 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02525 } else {
02526 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02527 }
02528
02529
02530 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02531
02532
02533 if (!ast_strlen_zero(authuser))
02534 ast_build_string(&t, &left, "/authuser=%s", authuser);
02535
02536
02537 if (!ast_strlen_zero(imapflags))
02538 ast_build_string(&t, &left, "/%s", imapflags);
02539
02540
02541 #if 1
02542 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02543 #else
02544 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02545 #endif
02546 if (box == NEW_FOLDER || box == OLD_FOLDER)
02547 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02548 else if (box == GREETINGS_FOLDER)
02549 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02550 else {
02551 if (!ast_strlen_zero(imapparentfolder)) {
02552
02553 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02554 } else {
02555 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02556 }
02557 }
02558 }
02559
02560 static int init_mailstream(struct vm_state *vms, int box)
02561 {
02562 MAILSTREAM *stream = NIL;
02563 long debug;
02564 char tmp[256];
02565
02566 if (!vms) {
02567 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02568 return -1;
02569 }
02570 if (option_debug > 2)
02571 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02572 if (vms->mailstream == NIL || !vms->mailstream) {
02573 if (option_debug)
02574 ast_log(LOG_DEBUG, "mailstream not set.\n");
02575 } else {
02576 stream = vms->mailstream;
02577 }
02578
02579 debug = NIL;
02580
02581 if (delimiter == '\0') {
02582 char *cp;
02583 #ifdef USE_SYSTEM_IMAP
02584 #include <imap/linkage.c>
02585 #elif defined(USE_SYSTEM_CCLIENT)
02586 #include <c-client/linkage.c>
02587 #else
02588 #include "linkage.c"
02589 #endif
02590
02591 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02592 ast_mutex_lock(&vms->lock);
02593 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02594 ast_mutex_unlock(&vms->lock);
02595 if (stream == NIL) {
02596 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02597 return -1;
02598 }
02599 get_mailbox_delimiter(stream);
02600
02601 for (cp = vms->imapfolder; *cp; cp++)
02602 if (*cp == '/')
02603 *cp = delimiter;
02604 }
02605
02606 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02607 if (option_debug > 2)
02608 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02609 ast_mutex_lock(&vms->lock);
02610 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02611 ast_mutex_unlock(&vms->lock);
02612 if (vms->mailstream == NIL) {
02613 return -1;
02614 } else {
02615 return 0;
02616 }
02617 }
02618
02619 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02620 {
02621 SEARCHPGM *pgm;
02622 SEARCHHEADER *hdr;
02623 int ret, urgent = 0;
02624
02625
02626 if (box == 11) {
02627 box = NEW_FOLDER;
02628 urgent = 1;
02629 }
02630
02631 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02632 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02633 vms->imapversion = vmu->imapversion;
02634 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02635
02636 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02637 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02638 return -1;
02639 }
02640
02641 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02642
02643
02644 if (box == 0) {
02645 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02646 check_quota(vms, (char *) mbox(vmu, box));
02647 }
02648
02649 ast_mutex_lock(&vms->lock);
02650 pgm = mail_newsearchpgm();
02651
02652
02653 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02654 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02655 pgm->header = hdr;
02656 pgm->deleted = 0;
02657 pgm->undeleted = 1;
02658
02659
02660 if (box == NEW_FOLDER && urgent == 1) {
02661 pgm->unseen = 1;
02662 pgm->seen = 0;
02663 pgm->flagged = 1;
02664 pgm->unflagged = 0;
02665 } else if (box == NEW_FOLDER && urgent == 0) {
02666 pgm->unseen = 1;
02667 pgm->seen = 0;
02668 pgm->flagged = 0;
02669 pgm->unflagged = 1;
02670 } else if (box == OLD_FOLDER) {
02671 pgm->seen = 1;
02672 pgm->unseen = 0;
02673 }
02674
02675 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02676
02677 vms->vmArrayIndex = 0;
02678 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02679 vms->lastmsg = vms->vmArrayIndex - 1;
02680 mail_free_searchpgm(&pgm);
02681
02682
02683
02684
02685 if (box == 0 && !vms->dh_arraysize) {
02686 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02687 }
02688 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02689 ast_mutex_unlock(&vms->lock);
02690 return -1;
02691 }
02692
02693 ast_mutex_unlock(&vms->lock);
02694 return 0;
02695 }
02696
02697 static void write_file(char *filename, char *buffer, unsigned long len)
02698 {
02699 FILE *output;
02700
02701 output = fopen (filename, "w");
02702 if (fwrite(buffer, len, 1, output) != 1) {
02703 if (ferror(output)) {
02704 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02705 }
02706 }
02707 fclose (output);
02708 }
02709
02710 static void update_messages_by_imapuser(const char *user, unsigned long number)
02711 {
02712 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02713
02714 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02715 return;
02716 }
02717
02718 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02719 vms->msgArray[vms->vmArrayIndex++] = number;
02720 }
02721
02722 void mm_searched(MAILSTREAM *stream, unsigned long number)
02723 {
02724 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02725
02726 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02727 return;
02728
02729 update_messages_by_imapuser(user, number);
02730 }
02731
02732 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02733 {
02734 struct ast_variable *var;
02735 struct ast_vm_user *vmu;
02736
02737 vmu = ast_calloc(1, sizeof *vmu);
02738 if (!vmu)
02739 return NULL;
02740 ast_set_flag(vmu, VM_ALLOCED);
02741 populate_defaults(vmu);
02742
02743 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02744 if (var) {
02745 apply_options_full(vmu, var);
02746 ast_variables_destroy(var);
02747 return vmu;
02748 } else {
02749 ast_free(vmu);
02750 return NULL;
02751 }
02752 }
02753
02754
02755
02756 void mm_exists(MAILSTREAM * stream, unsigned long number)
02757 {
02758
02759 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02760 if (number == 0) return;
02761 set_update(stream);
02762 }
02763
02764
02765 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02766 {
02767
02768 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02769 if (number == 0) return;
02770 set_update(stream);
02771 }
02772
02773
02774 void mm_flags(MAILSTREAM * stream, unsigned long number)
02775 {
02776
02777 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02778 if (number == 0) return;
02779 set_update(stream);
02780 }
02781
02782
02783 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02784 {
02785 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02786 mm_log (string, errflg);
02787 }
02788
02789
02790 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02791 {
02792 if (delimiter == '\0') {
02793 delimiter = delim;
02794 }
02795
02796 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02797 if (attributes & LATT_NOINFERIORS)
02798 ast_debug(5, "no inferiors\n");
02799 if (attributes & LATT_NOSELECT)
02800 ast_debug(5, "no select\n");
02801 if (attributes & LATT_MARKED)
02802 ast_debug(5, "marked\n");
02803 if (attributes & LATT_UNMARKED)
02804 ast_debug(5, "unmarked\n");
02805 }
02806
02807
02808 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02809 {
02810 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02811 if (attributes & LATT_NOINFERIORS)
02812 ast_debug(5, "no inferiors\n");
02813 if (attributes & LATT_NOSELECT)
02814 ast_debug(5, "no select\n");
02815 if (attributes & LATT_MARKED)
02816 ast_debug(5, "marked\n");
02817 if (attributes & LATT_UNMARKED)
02818 ast_debug(5, "unmarked\n");
02819 }
02820
02821
02822 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02823 {
02824 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02825 if (status->flags & SA_MESSAGES)
02826 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02827 if (status->flags & SA_RECENT)
02828 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02829 if (status->flags & SA_UNSEEN)
02830 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02831 if (status->flags & SA_UIDVALIDITY)
02832 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02833 if (status->flags & SA_UIDNEXT)
02834 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02835 ast_log(AST_LOG_NOTICE, "\n");
02836 }
02837
02838
02839 void mm_log(char *string, long errflg)
02840 {
02841 switch ((short) errflg) {
02842 case NIL:
02843 ast_debug(1, "IMAP Info: %s\n", string);
02844 break;
02845 case PARSE:
02846 case WARN:
02847 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02848 break;
02849 case ERROR:
02850 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02851 break;
02852 }
02853 }
02854
02855
02856 void mm_dlog(char *string)
02857 {
02858 ast_log(AST_LOG_NOTICE, "%s\n", string);
02859 }
02860
02861
02862 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02863 {
02864 struct ast_vm_user *vmu;
02865
02866 ast_debug(4, "Entering callback mm_login\n");
02867
02868 ast_copy_string(user, mb->user, MAILTMPLEN);
02869
02870
02871 if (!ast_strlen_zero(authpassword)) {
02872 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02873 } else {
02874 AST_LIST_TRAVERSE(&users, vmu, list) {
02875 if (!strcasecmp(mb->user, vmu->imapuser)) {
02876 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02877 break;
02878 }
02879 }
02880 if (!vmu) {
02881 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02882 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02883 free_user(vmu);
02884 }
02885 }
02886 }
02887 }
02888
02889
02890 void mm_critical(MAILSTREAM * stream)
02891 {
02892 }
02893
02894
02895 void mm_nocritical(MAILSTREAM * stream)
02896 {
02897 }
02898
02899
02900 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02901 {
02902 kill (getpid (), SIGSTOP);
02903 return NIL;
02904 }
02905
02906
02907 void mm_fatal(char *string)
02908 {
02909 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02910 }
02911
02912
02913 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02914 {
02915 struct vm_state *vms;
02916 char *mailbox = stream->mailbox, *user;
02917 char buf[1024] = "";
02918 unsigned long usage = 0, limit = 0;
02919
02920 while (pquota) {
02921 usage = pquota->usage;
02922 limit = pquota->limit;
02923 pquota = pquota->next;
02924 }
02925
02926 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)))) {
02927 ast_log(AST_LOG_ERROR, "No state found.\n");
02928 return;
02929 }
02930
02931 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02932
02933 vms->quota_usage = usage;
02934 vms->quota_limit = limit;
02935 }
02936
02937 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02938 {
02939 char *start, *eol_pnt;
02940 int taglen;
02941
02942 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02943 return NULL;
02944
02945 taglen = strlen(tag) + 1;
02946 if (taglen < 1)
02947 return NULL;
02948
02949 if (!(start = strstr(header, tag)))
02950 return NULL;
02951
02952
02953 memset(buf, 0, len);
02954
02955 ast_copy_string(buf, start+taglen, len);
02956 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02957 *eol_pnt = '\0';
02958 return buf;
02959 }
02960
02961 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02962 {
02963 char *start, *quote, *eol_pnt;
02964
02965 if (ast_strlen_zero(mailbox))
02966 return NULL;
02967
02968 if (!(start = strstr(mailbox, "/user=")))
02969 return NULL;
02970
02971 ast_copy_string(buf, start+6, len);
02972
02973 if (!(quote = strchr(buf, '\"'))) {
02974 if (!(eol_pnt = strchr(buf, '/')))
02975 eol_pnt = strchr(buf,'}');
02976 *eol_pnt = '\0';
02977 return buf;
02978 } else {
02979 eol_pnt = strchr(buf+1,'\"');
02980 *eol_pnt = '\0';
02981 return buf+1;
02982 }
02983 }
02984
02985 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02986 {
02987 struct vm_state *vms_p;
02988
02989 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02990 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02991 return vms_p;
02992 }
02993 if (option_debug > 4)
02994 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02995 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02996 return NULL;
02997 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02998 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
02999 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03000 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03001 vms_p->mailstream = NIL;
03002 vms_p->imapversion = vmu->imapversion;
03003 if (option_debug > 4)
03004 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03005 vms_p->updated = 1;
03006
03007 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03008 init_vm_state(vms_p);
03009 vmstate_insert(vms_p);
03010 return vms_p;
03011 }
03012
03013 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03014 {
03015 struct vmstate *vlist = NULL;
03016
03017 if (interactive) {
03018 struct vm_state *vms;
03019 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03020 vms = pthread_getspecific(ts_vmstate.key);
03021 return vms;
03022 }
03023
03024 AST_LIST_LOCK(&vmstates);
03025 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03026 if (!vlist->vms) {
03027 ast_debug(3, "error: vms is NULL for %s\n", user);
03028 continue;
03029 }
03030 if (vlist->vms->imapversion != imapversion) {
03031 continue;
03032 }
03033 if (!vlist->vms->imapuser) {
03034 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03035 continue;
03036 }
03037
03038 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03039 AST_LIST_UNLOCK(&vmstates);
03040 return vlist->vms;
03041 }
03042 }
03043 AST_LIST_UNLOCK(&vmstates);
03044
03045 ast_debug(3, "%s not found in vmstates\n", user);
03046
03047 return NULL;
03048 }
03049
03050 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03051 {
03052
03053 struct vmstate *vlist = NULL;
03054 const char *local_context = S_OR(context, "default");
03055
03056 if (interactive) {
03057 struct vm_state *vms;
03058 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03059 vms = pthread_getspecific(ts_vmstate.key);
03060 return vms;
03061 }
03062
03063 AST_LIST_LOCK(&vmstates);
03064 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03065 if (!vlist->vms) {
03066 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03067 continue;
03068 }
03069 if (vlist->vms->imapversion != imapversion) {
03070 continue;
03071 }
03072 if (!vlist->vms->username || !vlist->vms->context) {
03073 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03074 continue;
03075 }
03076
03077 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);
03078
03079 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03080 ast_debug(3, "Found it!\n");
03081 AST_LIST_UNLOCK(&vmstates);
03082 return vlist->vms;
03083 }
03084 }
03085 AST_LIST_UNLOCK(&vmstates);
03086
03087 ast_debug(3, "%s not found in vmstates\n", mailbox);
03088
03089 return NULL;
03090 }
03091
03092 static void vmstate_insert(struct vm_state *vms)
03093 {
03094 struct vmstate *v;
03095 struct vm_state *altvms;
03096
03097
03098
03099
03100 if (vms->interactive == 1) {
03101 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03102 if (altvms) {
03103 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03104 vms->newmessages = altvms->newmessages;
03105 vms->oldmessages = altvms->oldmessages;
03106 vms->vmArrayIndex = altvms->vmArrayIndex;
03107 vms->lastmsg = altvms->lastmsg;
03108 vms->curmsg = altvms->curmsg;
03109
03110 vms->persist_vms = altvms;
03111
03112 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03113 vms->mailstream = altvms->mailstream;
03114 #else
03115 vms->mailstream = NIL;
03116 #endif
03117 }
03118 return;
03119 }
03120
03121 if (!(v = ast_calloc(1, sizeof(*v))))
03122 return;
03123
03124 v->vms = vms;
03125
03126 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03127
03128 AST_LIST_LOCK(&vmstates);
03129 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03130 AST_LIST_UNLOCK(&vmstates);
03131 }
03132
03133 static void vmstate_delete(struct vm_state *vms)
03134 {
03135 struct vmstate *vc = NULL;
03136 struct vm_state *altvms = NULL;
03137
03138
03139
03140 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03141 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03142 altvms->newmessages = vms->newmessages;
03143 altvms->oldmessages = vms->oldmessages;
03144 altvms->updated = 1;
03145 vms->mailstream = mail_close(vms->mailstream);
03146
03147
03148 return;
03149 }
03150
03151 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03152
03153 AST_LIST_LOCK(&vmstates);
03154 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03155 if (vc->vms == vms) {
03156 AST_LIST_REMOVE_CURRENT(list);
03157 break;
03158 }
03159 }
03160 AST_LIST_TRAVERSE_SAFE_END
03161 AST_LIST_UNLOCK(&vmstates);
03162
03163 if (vc) {
03164 ast_mutex_destroy(&vc->vms->lock);
03165 ast_free(vc);
03166 }
03167 else
03168 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03169 }
03170
03171 static void set_update(MAILSTREAM * stream)
03172 {
03173 struct vm_state *vms;
03174 char *mailbox = stream->mailbox, *user;
03175 char buf[1024] = "";
03176
03177 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03178 if (user && option_debug > 2)
03179 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03180 return;
03181 }
03182
03183 ast_debug(3, "User %s mailbox set for update.\n", user);
03184
03185 vms->updated = 1;
03186 }
03187
03188 static void init_vm_state(struct vm_state *vms)
03189 {
03190 int x;
03191 vms->vmArrayIndex = 0;
03192 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03193 vms->msgArray[x] = 0;
03194 }
03195 ast_mutex_init(&vms->lock);
03196 }
03197
03198 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03199 {
03200 char *body_content;
03201 char *body_decoded;
03202 char *fn = is_intro ? vms->introfn : vms->fn;
03203 unsigned long len;
03204 unsigned long newlen;
03205 char filename[256];
03206
03207 if (!body || body == NIL)
03208 return -1;
03209
03210 ast_mutex_lock(&vms->lock);
03211 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03212 ast_mutex_unlock(&vms->lock);
03213 if (body_content != NIL) {
03214 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03215
03216 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03217
03218 if (!newlen) {
03219 return -1;
03220 }
03221 write_file(filename, (char *) body_decoded, newlen);
03222 } else {
03223 ast_debug(5, "Body of message is NULL.\n");
03224 return -1;
03225 }
03226 return 0;
03227 }
03228
03229
03230
03231
03232
03233
03234
03235
03236 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03237 char tmp[50];
03238 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03239 mail_list(stream, tmp, "*");
03240 }
03241
03242
03243
03244
03245
03246
03247
03248
03249 static void check_quota(struct vm_state *vms, char *mailbox) {
03250 ast_mutex_lock(&vms->lock);
03251 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03252 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03253 if (vms && vms->mailstream != NULL) {
03254 imap_getquotaroot(vms->mailstream, mailbox);
03255 } else {
03256 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03257 }
03258 ast_mutex_unlock(&vms->lock);
03259 }
03260
03261 #endif
03262
03263
03264
03265
03266
03267 static int vm_lock_path(const char *path)
03268 {
03269 switch (ast_lock_path(path)) {
03270 case AST_LOCK_TIMEOUT:
03271 return -1;
03272 default:
03273 return 0;
03274 }
03275 }
03276
03277
03278 #ifdef ODBC_STORAGE
03279 struct generic_prepare_struct {
03280 char *sql;
03281 int argc;
03282 char **argv;
03283 };
03284
03285 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03286 {
03287 struct generic_prepare_struct *gps = data;
03288 int res, i;
03289 SQLHSTMT stmt;
03290
03291 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03292 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03293 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03294 return NULL;
03295 }
03296 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03297 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03298 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03299 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03300 return NULL;
03301 }
03302 for (i = 0; i < gps->argc; i++)
03303 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03304
03305 return stmt;
03306 }
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322 static int retrieve_file(char *dir, int msgnum)
03323 {
03324 int x = 0;
03325 int res;
03326 int fd = -1;
03327 size_t fdlen = 0;
03328 void *fdm = MAP_FAILED;
03329 SQLSMALLINT colcount = 0;
03330 SQLHSTMT stmt;
03331 char sql[PATH_MAX];
03332 char fmt[80]="";
03333 char *c;
03334 char coltitle[256];
03335 SQLSMALLINT collen;
03336 SQLSMALLINT datatype;
03337 SQLSMALLINT decimaldigits;
03338 SQLSMALLINT nullable;
03339 SQLULEN colsize;
03340 SQLLEN colsize2;
03341 FILE *f = NULL;
03342 char rowdata[80];
03343 char fn[PATH_MAX];
03344 char full_fn[PATH_MAX];
03345 char msgnums[80];
03346 char *argv[] = { dir, msgnums };
03347 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03348
03349 struct odbc_obj *obj;
03350 obj = ast_odbc_request_obj(odbc_database, 0);
03351 if (obj) {
03352 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03353 c = strchr(fmt, '|');
03354 if (c)
03355 *c = '\0';
03356 if (!strcasecmp(fmt, "wav49"))
03357 strcpy(fmt, "WAV");
03358 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03359 if (msgnum > -1)
03360 make_file(fn, sizeof(fn), dir, msgnum);
03361 else
03362 ast_copy_string(fn, dir, sizeof(fn));
03363
03364
03365 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03366
03367 if (!(f = fopen(full_fn, "w+"))) {
03368 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03369 goto yuck;
03370 }
03371
03372 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03373 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03374 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03375 if (!stmt) {
03376 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03377 ast_odbc_release_obj(obj);
03378 goto yuck;
03379 }
03380 res = SQLFetch(stmt);
03381 if (res == SQL_NO_DATA) {
03382 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03383 ast_odbc_release_obj(obj);
03384 goto yuck;
03385 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03386 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03387 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03388 ast_odbc_release_obj(obj);
03389 goto yuck;
03390 }
03391 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03392 if (fd < 0) {
03393 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03394 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03395 ast_odbc_release_obj(obj);
03396 goto yuck;
03397 }
03398 res = SQLNumResultCols(stmt, &colcount);
03399 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03400 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03401 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03402 ast_odbc_release_obj(obj);
03403 goto yuck;
03404 }
03405 if (f)
03406 fprintf(f, "[message]\n");
03407 for (x = 0; x < colcount; x++) {
03408 rowdata[0] = '\0';
03409 colsize = 0;
03410 collen = sizeof(coltitle);
03411 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03412 &datatype, &colsize, &decimaldigits, &nullable);
03413 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03414 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03415 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03416 ast_odbc_release_obj(obj);
03417 goto yuck;
03418 }
03419 if (!strcasecmp(coltitle, "recording")) {
03420 off_t offset;
03421 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03422 fdlen = colsize2;
03423 if (fd > -1) {
03424 char tmp[1]="";
03425 lseek(fd, fdlen - 1, SEEK_SET);
03426 if (write(fd, tmp, 1) != 1) {
03427 close(fd);
03428 fd = -1;
03429 continue;
03430 }
03431
03432 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03433 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03434 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03435 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03436 ast_odbc_release_obj(obj);
03437 goto yuck;
03438 } else {
03439 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03440 munmap(fdm, CHUNKSIZE);
03441 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03442 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03443 unlink(full_fn);
03444 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03445 ast_odbc_release_obj(obj);
03446 goto yuck;
03447 }
03448 }
03449 }
03450 if (truncate(full_fn, fdlen) < 0) {
03451 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03452 }
03453 }
03454 } else {
03455 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03456 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03457 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03458 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03459 ast_odbc_release_obj(obj);
03460 goto yuck;
03461 }
03462 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03463 fprintf(f, "%s=%s\n", coltitle, rowdata);
03464 }
03465 }
03466 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03467 ast_odbc_release_obj(obj);
03468 } else
03469 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03470 yuck:
03471 if (f)
03472 fclose(f);
03473 if (fd > -1)
03474 close(fd);
03475 return x - 1;
03476 }
03477
03478
03479
03480
03481
03482
03483
03484
03485
03486
03487
03488
03489 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03490 {
03491 int x = 0;
03492 int res;
03493 SQLHSTMT stmt;
03494 char sql[PATH_MAX];
03495 char rowdata[20];
03496 char *argv[] = { dir };
03497 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03498
03499 struct odbc_obj *obj;
03500 obj = ast_odbc_request_obj(odbc_database, 0);
03501 if (obj) {
03502 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03503
03504 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03505 if (!stmt) {
03506 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03507 ast_odbc_release_obj(obj);
03508 goto yuck;
03509 }
03510 res = SQLFetch(stmt);
03511 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03512 if (res == SQL_NO_DATA) {
03513 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03514 } else {
03515 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03516 }
03517
03518 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03519 ast_odbc_release_obj(obj);
03520 goto yuck;
03521 }
03522 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03523 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03524 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03525 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03526 ast_odbc_release_obj(obj);
03527 goto yuck;
03528 }
03529 if (sscanf(rowdata, "%30d", &x) != 1)
03530 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03531 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03532 ast_odbc_release_obj(obj);
03533 return x;
03534 } else
03535 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03536 yuck:
03537 return x - 1;
03538 }
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548
03549 static int message_exists(char *dir, int msgnum)
03550 {
03551 int x = 0;
03552 int res;
03553 SQLHSTMT stmt;
03554 char sql[PATH_MAX];
03555 char rowdata[20];
03556 char msgnums[20];
03557 char *argv[] = { dir, msgnums };
03558 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03559
03560 struct odbc_obj *obj;
03561 obj = ast_odbc_request_obj(odbc_database, 0);
03562 if (obj) {
03563 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03564 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03565 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03566 if (!stmt) {
03567 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03568 ast_odbc_release_obj(obj);
03569 goto yuck;
03570 }
03571 res = SQLFetch(stmt);
03572 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03573 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03574 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03575 ast_odbc_release_obj(obj);
03576 goto yuck;
03577 }
03578 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03579 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03580 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03581 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03582 ast_odbc_release_obj(obj);
03583 goto yuck;
03584 }
03585 if (sscanf(rowdata, "%30d", &x) != 1)
03586 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03587 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03588 ast_odbc_release_obj(obj);
03589 } else
03590 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03591 yuck:
03592 return x;
03593 }
03594
03595
03596
03597
03598
03599
03600
03601
03602
03603
03604 static int count_messages(struct ast_vm_user *vmu, char *dir)
03605 {
03606 int x = 0;
03607 int res;
03608 SQLHSTMT stmt;
03609 char sql[PATH_MAX];
03610 char rowdata[20];
03611 char *argv[] = { dir };
03612 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03613
03614 struct odbc_obj *obj;
03615 obj = ast_odbc_request_obj(odbc_database, 0);
03616 if (obj) {
03617 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03618 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03619 if (!stmt) {
03620 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03621 ast_odbc_release_obj(obj);
03622 goto yuck;
03623 }
03624 res = SQLFetch(stmt);
03625 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03626 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03627 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03628 ast_odbc_release_obj(obj);
03629 goto yuck;
03630 }
03631 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03632 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03633 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03634 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03635 ast_odbc_release_obj(obj);
03636 goto yuck;
03637 }
03638 if (sscanf(rowdata, "%30d", &x) != 1)
03639 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03640 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03641 ast_odbc_release_obj(obj);
03642 return x;
03643 } else
03644 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03645 yuck:
03646 return x - 1;
03647
03648 }
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658
03659
03660 static void delete_file(const char *sdir, int smsg)
03661 {
03662 SQLHSTMT stmt;
03663 char sql[PATH_MAX];
03664 char msgnums[20];
03665 char *argv[] = { NULL, msgnums };
03666 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03667 struct odbc_obj *obj;
03668
03669 argv[0] = ast_strdupa(sdir);
03670
03671 obj = ast_odbc_request_obj(odbc_database, 0);
03672 if (obj) {
03673 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03674 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03675 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03676 if (!stmt)
03677 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03678 else
03679 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03680 ast_odbc_release_obj(obj);
03681 } else
03682 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03683 return;
03684 }
03685
03686
03687
03688
03689
03690
03691
03692
03693
03694
03695
03696
03697 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03698 {
03699 SQLHSTMT stmt;
03700 char sql[512];
03701 char msgnums[20];
03702 char msgnumd[20];
03703 struct odbc_obj *obj;
03704 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03705 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03706
03707 delete_file(ddir, dmsg);
03708 obj = ast_odbc_request_obj(odbc_database, 0);
03709 if (obj) {
03710 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03711 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03712 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);
03713 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03714 if (!stmt)
03715 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03716 else
03717 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03718 ast_odbc_release_obj(obj);
03719 } else
03720 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03721 return;
03722 }
03723
03724 struct insert_data {
03725 char *sql;
03726 const char *dir;
03727 const char *msgnums;
03728 void *data;
03729 SQLLEN datalen;
03730 SQLLEN indlen;
03731 const char *context;
03732 const char *macrocontext;
03733 const char *callerid;
03734 const char *origtime;
03735 const char *duration;
03736 const char *mailboxuser;
03737 const char *mailboxcontext;
03738 const char *category;
03739 const char *flag;
03740 };
03741
03742 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03743 {
03744 struct insert_data *data = vdata;
03745 int res;
03746 SQLHSTMT stmt;
03747
03748 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03749 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03750 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03751 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03752 return NULL;
03753 }
03754
03755 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03756 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03757 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03758 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03759 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03760 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03761 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03762 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03763 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03764 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03765 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03766 if (!ast_strlen_zero(data->category)) {
03767 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03768 }
03769 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03770 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03771 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03772 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03773 return NULL;
03774 }
03775
03776 return stmt;
03777 }
03778
03779
03780
03781
03782
03783
03784
03785
03786
03787
03788
03789
03790
03791
03792 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03793 {
03794 int res = 0;
03795 int fd = -1;
03796 void *fdm = MAP_FAILED;
03797 off_t fdlen = -1;
03798 SQLHSTMT stmt;
03799 char sql[PATH_MAX];
03800 char msgnums[20];
03801 char fn[PATH_MAX];
03802 char full_fn[PATH_MAX];
03803 char fmt[80]="";
03804 char *c;
03805 struct ast_config *cfg = NULL;
03806 struct odbc_obj *obj;
03807 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03808 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03809 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03810
03811 delete_file(dir, msgnum);
03812 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03813 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03814 return -1;
03815 }
03816
03817 do {
03818 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03819 c = strchr(fmt, '|');
03820 if (c)
03821 *c = '\0';
03822 if (!strcasecmp(fmt, "wav49"))
03823 strcpy(fmt, "WAV");
03824 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03825 if (msgnum > -1)
03826 make_file(fn, sizeof(fn), dir, msgnum);
03827 else
03828 ast_copy_string(fn, dir, sizeof(fn));
03829 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03830 cfg = ast_config_load(full_fn, config_flags);
03831 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03832 fd = open(full_fn, O_RDWR);
03833 if (fd < 0) {
03834 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03835 res = -1;
03836 break;
03837 }
03838 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03839 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03840 idata.context = "";
03841 }
03842 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03843 idata.macrocontext = "";
03844 }
03845 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03846 idata.callerid = "";
03847 }
03848 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03849 idata.origtime = "";
03850 }
03851 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03852 idata.duration = "";
03853 }
03854 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03855 idata.category = "";
03856 }
03857 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03858 idata.flag = "";
03859 }
03860 }
03861 fdlen = lseek(fd, 0, SEEK_END);
03862 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03863 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03864 res = -1;
03865 break;
03866 }
03867 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03868 if (fdm == MAP_FAILED) {
03869 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03870 res = -1;
03871 break;
03872 }
03873 idata.data = fdm;
03874 idata.datalen = idata.indlen = fdlen;
03875
03876 if (!ast_strlen_zero(idata.category))
03877 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03878 else
03879 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03880
03881 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03882 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03883 } else {
03884 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03885 res = -1;
03886 }
03887 } while (0);
03888 if (obj) {
03889 ast_odbc_release_obj(obj);
03890 }
03891 if (cfg)
03892 ast_config_destroy(cfg);
03893 if (fdm != MAP_FAILED)
03894 munmap(fdm, fdlen);
03895 if (fd > -1)
03896 close(fd);
03897 return res;
03898 }
03899
03900
03901
03902
03903
03904
03905
03906
03907
03908
03909
03910
03911
03912
03913 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03914 {
03915 SQLHSTMT stmt;
03916 char sql[PATH_MAX];
03917 char msgnums[20];
03918 char msgnumd[20];
03919 struct odbc_obj *obj;
03920 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03921 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03922
03923 delete_file(ddir, dmsg);
03924 obj = ast_odbc_request_obj(odbc_database, 0);
03925 if (obj) {
03926 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03927 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03928 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03929 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03930 if (!stmt)
03931 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03932 else
03933 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03934 ast_odbc_release_obj(obj);
03935 } else
03936 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03937 return;
03938 }
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949
03950
03951 static int remove_file(char *dir, int msgnum)
03952 {
03953 char fn[PATH_MAX];
03954 char full_fn[PATH_MAX];
03955 char msgnums[80];
03956
03957 if (msgnum > -1) {
03958 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03959 make_file(fn, sizeof(fn), dir, msgnum);
03960 } else
03961 ast_copy_string(fn, dir, sizeof(fn));
03962 ast_filedelete(fn, NULL);
03963 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03964 unlink(full_fn);
03965 return 0;
03966 }
03967 #else
03968 #ifndef IMAP_STORAGE
03969
03970
03971
03972
03973
03974
03975
03976
03977
03978 static int count_messages(struct ast_vm_user *vmu, char *dir)
03979 {
03980
03981 int vmcount = 0;
03982 DIR *vmdir = NULL;
03983 struct dirent *vment = NULL;
03984
03985 if (vm_lock_path(dir))
03986 return ERROR_LOCK_PATH;
03987
03988 if ((vmdir = opendir(dir))) {
03989 while ((vment = readdir(vmdir))) {
03990 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03991 vmcount++;
03992 }
03993 }
03994 closedir(vmdir);
03995 }
03996 ast_unlock_path(dir);
03997
03998 return vmcount;
03999 }
04000
04001
04002
04003
04004
04005
04006
04007
04008 static void rename_file(char *sfn, char *dfn)
04009 {
04010 char stxt[PATH_MAX];
04011 char dtxt[PATH_MAX];
04012 ast_filerename(sfn, dfn, NULL);
04013 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04014 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04015 if (ast_check_realtime("voicemail_data")) {
04016 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04017 }
04018 rename(stxt, dtxt);
04019 }
04020
04021
04022
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04033 {
04034 int x;
04035 unsigned char map[MAXMSGLIMIT] = "";
04036 DIR *msgdir;
04037 struct dirent *msgdirent;
04038 int msgdirint;
04039 char extension[4];
04040 int stopcount = 0;
04041
04042
04043
04044
04045
04046 if (!(msgdir = opendir(dir))) {
04047 return -1;
04048 }
04049
04050 while ((msgdirent = readdir(msgdir))) {
04051 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04052 map[msgdirint] = 1;
04053 stopcount++;
04054 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04055 }
04056 }
04057 closedir(msgdir);
04058
04059 for (x = 0; x < vmu->maxmsg; x++) {
04060 if (map[x] == 1) {
04061 stopcount--;
04062 } else if (map[x] == 0 && !stopcount) {
04063 break;
04064 }
04065 }
04066
04067 return x - 1;
04068 }
04069
04070 #endif
04071 #endif
04072 #ifndef IMAP_STORAGE
04073
04074
04075
04076
04077
04078
04079
04080
04081
04082
04083 static int copy(char *infile, char *outfile)
04084 {
04085 int ifd;
04086 int ofd;
04087 int res;
04088 int len;
04089 char buf[4096];
04090
04091 #ifdef HARDLINK_WHEN_POSSIBLE
04092
04093 if (link(infile, outfile)) {
04094 #endif
04095 if ((ifd = open(infile, O_RDONLY)) < 0) {
04096 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04097 return -1;
04098 }
04099 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04100 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04101 close(ifd);
04102 return -1;
04103 }
04104 do {
04105 len = read(ifd, buf, sizeof(buf));
04106 if (len < 0) {
04107 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04108 close(ifd);
04109 close(ofd);
04110 unlink(outfile);
04111 } else if (len) {
04112 res = write(ofd, buf, len);
04113 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04114 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04115 close(ifd);
04116 close(ofd);
04117 unlink(outfile);
04118 }
04119 }
04120 } while (len);
04121 close(ifd);
04122 close(ofd);
04123 return 0;
04124 #ifdef HARDLINK_WHEN_POSSIBLE
04125 } else {
04126
04127 return 0;
04128 }
04129 #endif
04130 }
04131
04132
04133
04134
04135
04136
04137
04138
04139
04140
04141 static void copy_plain_file(char *frompath, char *topath)
04142 {
04143 char frompath2[PATH_MAX], topath2[PATH_MAX];
04144 struct ast_variable *tmp,*var = NULL;
04145 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04146 ast_filecopy(frompath, topath, NULL);
04147 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04148 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04149 if (ast_check_realtime("voicemail_data")) {
04150 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04151
04152 for (tmp = var; tmp; tmp = tmp->next) {
04153 if (!strcasecmp(tmp->name, "origmailbox")) {
04154 origmailbox = tmp->value;
04155 } else if (!strcasecmp(tmp->name, "context")) {
04156 context = tmp->value;
04157 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04158 macrocontext = tmp->value;
04159 } else if (!strcasecmp(tmp->name, "exten")) {
04160 exten = tmp->value;
04161 } else if (!strcasecmp(tmp->name, "priority")) {
04162 priority = tmp->value;
04163 } else if (!strcasecmp(tmp->name, "callerchan")) {
04164 callerchan = tmp->value;
04165 } else if (!strcasecmp(tmp->name, "callerid")) {
04166 callerid = tmp->value;
04167 } else if (!strcasecmp(tmp->name, "origdate")) {
04168 origdate = tmp->value;
04169 } else if (!strcasecmp(tmp->name, "origtime")) {
04170 origtime = tmp->value;
04171 } else if (!strcasecmp(tmp->name, "category")) {
04172 category = tmp->value;
04173 } else if (!strcasecmp(tmp->name, "duration")) {
04174 duration = tmp->value;
04175 }
04176 }
04177 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);
04178 }
04179 copy(frompath2, topath2);
04180 ast_variables_destroy(var);
04181 }
04182 #endif
04183
04184
04185
04186
04187
04188
04189
04190
04191
04192 static int vm_delete(char *file)
04193 {
04194 char *txt;
04195 int txtsize = 0;
04196
04197 txtsize = (strlen(file) + 5)*sizeof(char);
04198 txt = alloca(txtsize);
04199
04200
04201
04202 if (ast_check_realtime("voicemail_data")) {
04203 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04204 }
04205 snprintf(txt, txtsize, "%s.txt", file);
04206 unlink(txt);
04207 return ast_filedelete(file, NULL);
04208 }
04209
04210
04211
04212
04213 static int inbuf(struct baseio *bio, FILE *fi)
04214 {
04215 int l;
04216
04217 if (bio->ateof)
04218 return 0;
04219
04220 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04221 if (ferror(fi))
04222 return -1;
04223
04224 bio->ateof = 1;
04225 return 0;
04226 }
04227
04228 bio->iolen = l;
04229 bio->iocp = 0;
04230
04231 return 1;
04232 }
04233
04234
04235
04236
04237 static int inchar(struct baseio *bio, FILE *fi)
04238 {
04239 if (bio->iocp>=bio->iolen) {
04240 if (!inbuf(bio, fi))
04241 return EOF;
04242 }
04243
04244 return bio->iobuf[bio->iocp++];
04245 }
04246
04247
04248
04249
04250 static int ochar(struct baseio *bio, int c, FILE *so)
04251 {
04252 if (bio->linelength >= BASELINELEN) {
04253 if (fputs(ENDL, so) == EOF) {
04254 return -1;
04255 }
04256
04257 bio->linelength = 0;
04258 }
04259
04260 if (putc(((unsigned char) c), so) == EOF) {
04261 return -1;
04262 }
04263
04264 bio->linelength++;
04265
04266 return 1;
04267 }
04268
04269
04270
04271
04272
04273
04274
04275
04276
04277
04278 static int base_encode(char *filename, FILE *so)
04279 {
04280 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04281 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04282 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04283 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04284 int i, hiteof = 0;
04285 FILE *fi;
04286 struct baseio bio;
04287
04288 memset(&bio, 0, sizeof(bio));
04289 bio.iocp = BASEMAXINLINE;
04290
04291 if (!(fi = fopen(filename, "rb"))) {
04292 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04293 return -1;
04294 }
04295
04296 while (!hiteof){
04297 unsigned char igroup[3], ogroup[4];
04298 int c, n;
04299
04300 memset(igroup, 0, sizeof(igroup));
04301
04302 for (n = 0; n < 3; n++) {
04303 if ((c = inchar(&bio, fi)) == EOF) {
04304 hiteof = 1;
04305 break;
04306 }
04307
04308 igroup[n] = (unsigned char) c;
04309 }
04310
04311 if (n > 0) {
04312 ogroup[0]= dtable[igroup[0] >> 2];
04313 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04314 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04315 ogroup[3]= dtable[igroup[2] & 0x3F];
04316
04317 if (n < 3) {
04318 ogroup[3] = '=';
04319
04320 if (n < 2)
04321 ogroup[2] = '=';
04322 }
04323
04324 for (i = 0; i < 4; i++)
04325 ochar(&bio, ogroup[i], so);
04326 }
04327 }
04328
04329 fclose(fi);
04330
04331 if (fputs(ENDL, so) == EOF) {
04332 return 0;
04333 }
04334
04335 return 1;
04336 }
04337
04338 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)
04339 {
04340 char callerid[256];
04341 char num[12];
04342 char fromdir[256], fromfile[256];
04343 struct ast_config *msg_cfg;
04344 const char *origcallerid, *origtime;
04345 char origcidname[80], origcidnum[80], origdate[80];
04346 int inttime;
04347 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04348
04349
04350 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04351 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04352 snprintf(num, sizeof(num), "%d", msgnum);
04353 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04354 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04355 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04356 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04357 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04358 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04359 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04360 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04361 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04362 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04363
04364
04365 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04366 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04367 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04368 strcat(fromfile, ".txt");
04369 }
04370 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04371 if (option_debug > 0) {
04372 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04373 }
04374 return;
04375 }
04376
04377 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04378 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04379 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04380 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04381 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04382 }
04383
04384 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04385 struct timeval tv = { inttime, };
04386 struct ast_tm tm;
04387 ast_localtime(&tv, &tm, NULL);
04388 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04389 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04390 }
04391 ast_config_destroy(msg_cfg);
04392 }
04393
04394
04395
04396
04397
04398
04399
04400
04401
04402 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04403 {
04404 const char *ptr;
04405
04406
04407 ast_str_set(buf, maxlen, "\"");
04408 for (ptr = from; *ptr; ptr++) {
04409 if (*ptr == '"' || *ptr == '\\') {
04410 ast_str_append(buf, maxlen, "\\%c", *ptr);
04411 } else {
04412 ast_str_append(buf, maxlen, "%c", *ptr);
04413 }
04414 }
04415 ast_str_append(buf, maxlen, "\"");
04416
04417 return ast_str_buffer(*buf);
04418 }
04419
04420
04421
04422
04423
04424 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04425 {
04426 const struct vm_zone *z = NULL;
04427 struct timeval t = ast_tvnow();
04428
04429
04430 if (!ast_strlen_zero(vmu->zonetag)) {
04431
04432 AST_LIST_LOCK(&zones);
04433 AST_LIST_TRAVERSE(&zones, z, list) {
04434 if (!strcmp(z->name, vmu->zonetag))
04435 break;
04436 }
04437 AST_LIST_UNLOCK(&zones);
04438 }
04439 ast_localtime(&t, tm, z ? z->timezone : NULL);
04440 return tm;
04441 }
04442
04443
04444
04445
04446
04447 static int check_mime(const char *str)
04448 {
04449 for (; *str; str++) {
04450 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04451 return 1;
04452 }
04453 }
04454 return 0;
04455 }
04456
04457
04458
04459
04460
04461
04462
04463
04464
04465
04466
04467
04468
04469
04470
04471
04472
04473
04474 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04475 {
04476 struct ast_str *tmp = ast_str_alloca(80);
04477 int first_section = 1;
04478
04479 ast_str_reset(*end);
04480 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04481 for (; *start; start++) {
04482 int need_encoding = 0;
04483 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04484 need_encoding = 1;
04485 }
04486 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04487 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04488 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04489 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04490
04491 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04492 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04493 first_section = 0;
04494 }
04495 if (need_encoding && *start == ' ') {
04496 ast_str_append(&tmp, -1, "_");
04497 } else if (need_encoding) {
04498 ast_str_append(&tmp, -1, "=%hhX", *start);
04499 } else {
04500 ast_str_append(&tmp, -1, "%c", *start);
04501 }
04502 }
04503 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04504 return ast_str_buffer(*end);
04505 }
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526
04527
04528
04529
04530 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)
04531 {
04532 char date[256];
04533 char host[MAXHOSTNAMELEN] = "";
04534 char who[256];
04535 char bound[256];
04536 char dur[256];
04537 struct ast_tm tm;
04538 char enc_cidnum[256] = "", enc_cidname[256] = "";
04539 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04540 char *greeting_attachment;
04541 char filename[256];
04542
04543 if (!str1 || !str2) {
04544 ast_free(str1);
04545 ast_free(str2);
04546 return;
04547 }
04548
04549 if (cidnum) {
04550 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04551 }
04552 if (cidname) {
04553 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04554 }
04555 gethostname(host, sizeof(host) - 1);
04556
04557 if (strchr(srcemail, '@')) {
04558 ast_copy_string(who, srcemail, sizeof(who));
04559 } else {
04560 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04561 }
04562
04563 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04564 if (greeting_attachment) {
04565 *greeting_attachment++ = '\0';
04566 }
04567
04568 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04569 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04570 fprintf(p, "Date: %s" ENDL, date);
04571
04572
04573 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04574
04575 if (!ast_strlen_zero(fromstring)) {
04576 struct ast_channel *ast;
04577 if ((ast = ast_dummy_channel_alloc())) {
04578 char *ptr;
04579 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04580 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04581
04582 if (check_mime(ast_str_buffer(str1))) {
04583 int first_line = 1;
04584 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04585 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04586 *ptr = '\0';
04587 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04588 first_line = 0;
04589
04590 ast_str_set(&str2, 0, "%s", ptr + 1);
04591 }
04592 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04593 } else {
04594 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04595 }
04596 ast = ast_channel_unref(ast);
04597 } else {
04598 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04599 }
04600 } else {
04601 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04602 }
04603
04604 if (check_mime(vmu->fullname)) {
04605 int first_line = 1;
04606 char *ptr;
04607 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04608 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04609 *ptr = '\0';
04610 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04611 first_line = 0;
04612
04613 ast_str_set(&str2, 0, "%s", ptr + 1);
04614 }
04615 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04616 } else {
04617 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04618 }
04619
04620 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04621 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04622 struct ast_channel *ast;
04623 if ((ast = ast_dummy_channel_alloc())) {
04624 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04625 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04626 if (check_mime(ast_str_buffer(str1))) {
04627 int first_line = 1;
04628 char *ptr;
04629 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04630 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04631 *ptr = '\0';
04632 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04633 first_line = 0;
04634
04635 ast_str_set(&str2, 0, "%s", ptr + 1);
04636 }
04637 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04638 } else {
04639 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
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 if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04646 if (ast_strlen_zero(flag)) {
04647 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04648 } else {
04649 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04650 }
04651 } else {
04652 if (ast_strlen_zero(flag)) {
04653 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04654 } else {
04655 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04656 }
04657 }
04658
04659 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04660 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04661 if (imap) {
04662
04663 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04664
04665 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04666 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04667 #ifdef IMAP_STORAGE
04668 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04669 #else
04670 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04671 #endif
04672
04673 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04674 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04675 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04676 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04677 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04678 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04679 if (!ast_strlen_zero(category)) {
04680 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04681 } else {
04682 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04683 }
04684 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04685 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04686 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04687 }
04688 if (!ast_strlen_zero(cidnum)) {
04689 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04690 }
04691 if (!ast_strlen_zero(cidname)) {
04692 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04693 }
04694 fprintf(p, "MIME-Version: 1.0" ENDL);
04695 if (attach_user_voicemail) {
04696
04697 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04698 (int) getpid(), (unsigned int) ast_random());
04699
04700 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04701 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04702 fprintf(p, "--%s" ENDL, bound);
04703 }
04704 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04705 if (emailbody || vmu->emailbody) {
04706 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04707 struct ast_channel *ast;
04708 if ((ast = ast_dummy_channel_alloc())) {
04709 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04710 ast_str_substitute_variables(&str1, 0, ast, e_body);
04711 #ifdef IMAP_STORAGE
04712 {
04713
04714 char *line = ast_str_buffer(str1), *next;
04715 do {
04716
04717 if ((next = strchr(line, '\n'))) {
04718 *next++ = '\0';
04719 }
04720 fprintf(p, "%s" ENDL, line);
04721 line = next;
04722 } while (!ast_strlen_zero(line));
04723 }
04724 #else
04725 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04726 #endif
04727 ast = ast_channel_unref(ast);
04728 } else {
04729 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04730 }
04731 } else if (msgnum > -1) {
04732 if (strcmp(vmu->mailbox, mailbox)) {
04733
04734 struct ast_config *msg_cfg;
04735 const char *v;
04736 int inttime;
04737 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04738 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04739
04740 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04741 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04742 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04743 strcat(fromfile, ".txt");
04744 }
04745 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04746 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04747 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04748 }
04749
04750
04751
04752 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04753 struct timeval tv = { inttime, };
04754 struct ast_tm tm;
04755 ast_localtime(&tv, &tm, NULL);
04756 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04757 }
04758 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04759 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04760 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04761 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04762 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04763 date, origcallerid, origdate);
04764 ast_config_destroy(msg_cfg);
04765 } else {
04766 goto plain_message;
04767 }
04768 } else {
04769 plain_message:
04770 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04771 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04772 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04773 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04774 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04775 }
04776 } else {
04777 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04778 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04779 }
04780
04781 if (imap || attach_user_voicemail) {
04782 if (!ast_strlen_zero(attach2)) {
04783 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04784 ast_debug(5, "creating second attachment filename %s\n", filename);
04785 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04786 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04787 ast_debug(5, "creating attachment filename %s\n", filename);
04788 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04789 } else {
04790 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04791 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04792 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04793 }
04794 }
04795 ast_free(str1);
04796 ast_free(str2);
04797 }
04798
04799 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)
04800 {
04801 char tmpdir[256], newtmp[256];
04802 char fname[256];
04803 char tmpcmd[256];
04804 int tmpfd = -1;
04805 int soxstatus = 0;
04806
04807
04808 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04809
04810 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04811 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04812 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04813 tmpfd = mkstemp(newtmp);
04814 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04815 ast_debug(3, "newtmp: %s\n", newtmp);
04816 if (tmpfd > -1) {
04817 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04818 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04819 attach = newtmp;
04820 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04821 } else {
04822 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04823 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04824 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04825 }
04826 }
04827 }
04828 fprintf(p, "--%s" ENDL, bound);
04829 if (msgnum > -1)
04830 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04831 else
04832 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04833 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04834 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04835 if (msgnum > -1)
04836 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04837 else
04838 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04839 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04840 base_encode(fname, p);
04841 if (last)
04842 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04843 if (tmpfd > -1) {
04844 if (soxstatus == 0) {
04845 unlink(fname);
04846 }
04847 close(tmpfd);
04848 unlink(newtmp);
04849 }
04850 return 0;
04851 }
04852
04853 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)
04854 {
04855 FILE *p = NULL;
04856 char tmp[80] = "/tmp/astmail-XXXXXX";
04857 char tmp2[256];
04858 char *stringp;
04859
04860 if (vmu && ast_strlen_zero(vmu->email)) {
04861 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04862 return(0);
04863 }
04864
04865
04866 format = ast_strdupa(format);
04867 stringp = format;
04868 strsep(&stringp, "|");
04869
04870 if (!strcmp(format, "wav49"))
04871 format = "WAV";
04872 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04873
04874
04875 if ((p = vm_mkftemp(tmp)) == NULL) {
04876 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04877 return -1;
04878 } else {
04879 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04880 fclose(p);
04881 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04882 ast_safe_system(tmp2);
04883 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04884 }
04885 return 0;
04886 }
04887
04888 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)
04889 {
04890 char enc_cidnum[256], enc_cidname[256];
04891 char date[256];
04892 char host[MAXHOSTNAMELEN] = "";
04893 char who[256];
04894 char dur[PATH_MAX];
04895 char tmp[80] = "/tmp/astmail-XXXXXX";
04896 char tmp2[PATH_MAX];
04897 struct ast_tm tm;
04898 FILE *p;
04899 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04900
04901 if (!str1 || !str2) {
04902 ast_free(str1);
04903 ast_free(str2);
04904 return -1;
04905 }
04906
04907 if (cidnum) {
04908 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04909 }
04910 if (cidname) {
04911 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04912 }
04913
04914 if ((p = vm_mkftemp(tmp)) == NULL) {
04915 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04916 ast_free(str1);
04917 ast_free(str2);
04918 return -1;
04919 }
04920 gethostname(host, sizeof(host)-1);
04921 if (strchr(srcemail, '@')) {
04922 ast_copy_string(who, srcemail, sizeof(who));
04923 } else {
04924 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04925 }
04926 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04927 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04928 fprintf(p, "Date: %s\n", date);
04929
04930
04931 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04932
04933 if (!ast_strlen_zero(pagerfromstring)) {
04934 struct ast_channel *ast;
04935 if ((ast = ast_dummy_channel_alloc())) {
04936 char *ptr;
04937 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04938 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04939
04940 if (check_mime(ast_str_buffer(str1))) {
04941 int first_line = 1;
04942 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04943 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04944 *ptr = '\0';
04945 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04946 first_line = 0;
04947
04948 ast_str_set(&str2, 0, "%s", ptr + 1);
04949 }
04950 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04951 } else {
04952 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04953 }
04954 ast = ast_channel_unref(ast);
04955 } else {
04956 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04957 }
04958 } else {
04959 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04960 }
04961
04962 if (check_mime(vmu->fullname)) {
04963 int first_line = 1;
04964 char *ptr;
04965 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04966 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04967 *ptr = '\0';
04968 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04969 first_line = 0;
04970
04971 ast_str_set(&str2, 0, "%s", ptr + 1);
04972 }
04973 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04974 } else {
04975 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04976 }
04977
04978 if (!ast_strlen_zero(pagersubject)) {
04979 struct ast_channel *ast;
04980 if ((ast = ast_dummy_channel_alloc())) {
04981 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04982 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04983 if (check_mime(ast_str_buffer(str1))) {
04984 int first_line = 1;
04985 char *ptr;
04986 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04987 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04988 *ptr = '\0';
04989 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04990 first_line = 0;
04991
04992 ast_str_set(&str2, 0, "%s", ptr + 1);
04993 }
04994 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04995 } else {
04996 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04997 }
04998 ast = ast_channel_unref(ast);
04999 } else {
05000 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05001 }
05002 } else {
05003 if (ast_strlen_zero(flag)) {
05004 fprintf(p, "Subject: New VM\n\n");
05005 } else {
05006 fprintf(p, "Subject: New %s VM\n\n", flag);
05007 }
05008 }
05009
05010 if (pagerbody) {
05011 struct ast_channel *ast;
05012 if ((ast = ast_dummy_channel_alloc())) {
05013 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05014 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05015 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05016 ast = ast_channel_unref(ast);
05017 } else {
05018 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05019 }
05020 } else {
05021 fprintf(p, "New %s long %s msg in box %s\n"
05022 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05023 }
05024
05025 fclose(p);
05026 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05027 ast_safe_system(tmp2);
05028 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05029 ast_free(str1);
05030 ast_free(str2);
05031 return 0;
05032 }
05033
05034
05035
05036
05037
05038
05039
05040
05041
05042
05043 static int get_date(char *s, int len)
05044 {
05045 struct ast_tm tm;
05046 struct timeval t = ast_tvnow();
05047
05048 ast_localtime(&t, &tm, "UTC");
05049
05050 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05051 }
05052
05053 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05054 {
05055 int res;
05056 char fn[PATH_MAX];
05057 char dest[PATH_MAX];
05058
05059 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05060
05061 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05062 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05063 return -1;
05064 }
05065
05066 RETRIEVE(fn, -1, ext, context);
05067 if (ast_fileexists(fn, NULL, NULL) > 0) {
05068 res = ast_stream_and_wait(chan, fn, ecodes);
05069 if (res) {
05070 DISPOSE(fn, -1);
05071 return res;
05072 }
05073 } else {
05074
05075 DISPOSE(fn, -1);
05076 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05077 if (res)
05078 return res;
05079 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05080 if (res)
05081 return res;
05082 }
05083 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05084 return res;
05085 }
05086
05087 static void free_zone(struct vm_zone *z)
05088 {
05089 ast_free(z);
05090 }
05091
05092 #ifdef ODBC_STORAGE
05093 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05094 {
05095 int x = -1;
05096 int res;
05097 SQLHSTMT stmt = NULL;
05098 char sql[PATH_MAX];
05099 char rowdata[20];
05100 char tmp[PATH_MAX] = "";
05101 struct odbc_obj *obj = NULL;
05102 char *context;
05103 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05104
05105 if (newmsgs)
05106 *newmsgs = 0;
05107 if (oldmsgs)
05108 *oldmsgs = 0;
05109 if (urgentmsgs)
05110 *urgentmsgs = 0;
05111
05112
05113 if (ast_strlen_zero(mailbox))
05114 return 0;
05115
05116 ast_copy_string(tmp, mailbox, sizeof(tmp));
05117
05118 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05119 int u, n, o;
05120 char *next, *remaining = tmp;
05121 while ((next = strsep(&remaining, " ,"))) {
05122 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05123 return -1;
05124 }
05125 if (urgentmsgs) {
05126 *urgentmsgs += u;
05127 }
05128 if (newmsgs) {
05129 *newmsgs += n;
05130 }
05131 if (oldmsgs) {
05132 *oldmsgs += o;
05133 }
05134 }
05135 return 0;
05136 }
05137
05138 context = strchr(tmp, '@');
05139 if (context) {
05140 *context = '\0';
05141 context++;
05142 } else
05143 context = "default";
05144
05145 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05146 do {
05147 if (newmsgs) {
05148 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05149 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05150 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05151 break;
05152 }
05153 res = SQLFetch(stmt);
05154 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05155 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05156 break;
05157 }
05158 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05159 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05160 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05161 break;
05162 }
05163 *newmsgs = atoi(rowdata);
05164 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05165 }
05166
05167 if (oldmsgs) {
05168 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05169 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05170 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05171 break;
05172 }
05173 res = SQLFetch(stmt);
05174 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05175 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05176 break;
05177 }
05178 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05179 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05180 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05181 break;
05182 }
05183 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05184 *oldmsgs = atoi(rowdata);
05185 }
05186
05187 if (urgentmsgs) {
05188 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05189 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05190 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05191 break;
05192 }
05193 res = SQLFetch(stmt);
05194 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05195 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05196 break;
05197 }
05198 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05199 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05200 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05201 break;
05202 }
05203 *urgentmsgs = atoi(rowdata);
05204 }
05205
05206 x = 0;
05207 } while (0);
05208 } else {
05209 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05210 }
05211
05212 if (stmt) {
05213 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05214 }
05215 if (obj) {
05216 ast_odbc_release_obj(obj);
05217 }
05218 return x;
05219 }
05220
05221
05222
05223
05224
05225
05226
05227
05228
05229
05230 static int messagecount(const char *context, const char *mailbox, const char *folder)
05231 {
05232 struct odbc_obj *obj = NULL;
05233 int nummsgs = 0;
05234 int res;
05235 SQLHSTMT stmt = NULL;
05236 char sql[PATH_MAX];
05237 char rowdata[20];
05238 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05239 if (!folder)
05240 folder = "INBOX";
05241
05242 if (ast_strlen_zero(mailbox))
05243 return 0;
05244
05245 obj = ast_odbc_request_obj(odbc_database, 0);
05246 if (obj) {
05247 if (!strcmp(folder, "INBOX")) {
05248 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);
05249 } else {
05250 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05251 }
05252 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05253 if (!stmt) {
05254 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05255 goto yuck;
05256 }
05257 res = SQLFetch(stmt);
05258 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05259 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05260 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05261 goto yuck;
05262 }
05263 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05264 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05265 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05266 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05267 goto yuck;
05268 }
05269 nummsgs = atoi(rowdata);
05270 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05271 } else
05272 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05273
05274 yuck:
05275 if (obj)
05276 ast_odbc_release_obj(obj);
05277 return nummsgs;
05278 }
05279
05280
05281
05282
05283
05284
05285
05286
05287
05288 static int has_voicemail(const char *mailbox, const char *folder)
05289 {
05290 char tmp[256], *tmp2 = tmp, *box, *context;
05291 ast_copy_string(tmp, mailbox, sizeof(tmp));
05292 while ((context = box = strsep(&tmp2, ",&"))) {
05293 strsep(&context, "@");
05294 if (ast_strlen_zero(context))
05295 context = "default";
05296 if (messagecount(context, box, folder))
05297 return 1;
05298 }
05299 return 0;
05300 }
05301 #endif
05302 #ifndef IMAP_STORAGE
05303
05304
05305
05306
05307
05308
05309
05310
05311
05312
05313
05314
05315
05316
05317
05318
05319 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)
05320 {
05321 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05322 const char *frombox = mbox(vmu, imbox);
05323 const char *userfolder;
05324 int recipmsgnum;
05325 int res = 0;
05326
05327 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05328
05329 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05330 userfolder = "Urgent";
05331 } else {
05332 userfolder = "INBOX";
05333 }
05334
05335 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05336
05337 if (!dir)
05338 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05339 else
05340 ast_copy_string(fromdir, dir, sizeof(fromdir));
05341
05342 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05343 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05344
05345 if (vm_lock_path(todir))
05346 return ERROR_LOCK_PATH;
05347
05348 recipmsgnum = last_message_index(recip, todir) + 1;
05349 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05350 make_file(topath, sizeof(topath), todir, recipmsgnum);
05351 #ifndef ODBC_STORAGE
05352 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05353 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05354 } else {
05355 #endif
05356
05357
05358
05359 copy_plain_file(frompath, topath);
05360 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05361 vm_delete(topath);
05362 #ifndef ODBC_STORAGE
05363 }
05364 #endif
05365 } else {
05366 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05367 res = -1;
05368 }
05369 ast_unlock_path(todir);
05370 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05371 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05372 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05373 flag);
05374
05375 return res;
05376 }
05377 #endif
05378 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05379
05380 static int messagecount(const char *context, const char *mailbox, const char *folder)
05381 {
05382 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05383 }
05384
05385 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05386 {
05387 DIR *dir;
05388 struct dirent *de;
05389 char fn[256];
05390 int ret = 0;
05391
05392
05393 if (ast_strlen_zero(mailbox))
05394 return 0;
05395
05396 if (ast_strlen_zero(folder))
05397 folder = "INBOX";
05398 if (ast_strlen_zero(context))
05399 context = "default";
05400
05401 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05402
05403 if (!(dir = opendir(fn)))
05404 return 0;
05405
05406 while ((de = readdir(dir))) {
05407 if (!strncasecmp(de->d_name, "msg", 3)) {
05408 if (shortcircuit) {
05409 ret = 1;
05410 break;
05411 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05412 ret++;
05413 }
05414 }
05415 }
05416
05417 closedir(dir);
05418
05419 return ret;
05420 }
05421
05422
05423
05424
05425
05426
05427
05428
05429
05430
05431 static int has_voicemail(const char *mailbox, const char *folder)
05432 {
05433 char tmp[256], *tmp2 = tmp, *box, *context;
05434 ast_copy_string(tmp, mailbox, sizeof(tmp));
05435 if (ast_strlen_zero(folder)) {
05436 folder = "INBOX";
05437 }
05438 while ((box = strsep(&tmp2, ",&"))) {
05439 if ((context = strchr(box, '@')))
05440 *context++ = '\0';
05441 else
05442 context = "default";
05443 if (__has_voicemail(context, box, folder, 1))
05444 return 1;
05445
05446 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05447 return 1;
05448 }
05449 }
05450 return 0;
05451 }
05452
05453
05454 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05455 {
05456 char tmp[256];
05457 char *context;
05458
05459
05460 if (ast_strlen_zero(mailbox))
05461 return 0;
05462
05463 if (newmsgs)
05464 *newmsgs = 0;
05465 if (oldmsgs)
05466 *oldmsgs = 0;
05467 if (urgentmsgs)
05468 *urgentmsgs = 0;
05469
05470 if (strchr(mailbox, ',')) {
05471 int tmpnew, tmpold, tmpurgent;
05472 char *mb, *cur;
05473
05474 ast_copy_string(tmp, mailbox, sizeof(tmp));
05475 mb = tmp;
05476 while ((cur = strsep(&mb, ", "))) {
05477 if (!ast_strlen_zero(cur)) {
05478 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05479 return -1;
05480 else {
05481 if (newmsgs)
05482 *newmsgs += tmpnew;
05483 if (oldmsgs)
05484 *oldmsgs += tmpold;
05485 if (urgentmsgs)
05486 *urgentmsgs += tmpurgent;
05487 }
05488 }
05489 }
05490 return 0;
05491 }
05492
05493 ast_copy_string(tmp, mailbox, sizeof(tmp));
05494
05495 if ((context = strchr(tmp, '@')))
05496 *context++ = '\0';
05497 else
05498 context = "default";
05499
05500 if (newmsgs)
05501 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05502 if (oldmsgs)
05503 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05504 if (urgentmsgs)
05505 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05506
05507 return 0;
05508 }
05509
05510 #endif
05511
05512
05513 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05514 {
05515 int urgentmsgs = 0;
05516 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05517 if (newmsgs) {
05518 *newmsgs += urgentmsgs;
05519 }
05520 return res;
05521 }
05522
05523 static void run_externnotify(char *context, char *extension, const char *flag)
05524 {
05525 char arguments[255];
05526 char ext_context[256] = "";
05527 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05528 struct ast_smdi_mwi_message *mwi_msg;
05529
05530 if (!ast_strlen_zero(context))
05531 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05532 else
05533 ast_copy_string(ext_context, extension, sizeof(ext_context));
05534
05535 if (smdi_iface) {
05536 if (ast_app_has_voicemail(ext_context, NULL))
05537 ast_smdi_mwi_set(smdi_iface, extension);
05538 else
05539 ast_smdi_mwi_unset(smdi_iface, extension);
05540
05541 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05542 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05543 if (!strncmp(mwi_msg->cause, "INV", 3))
05544 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05545 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05546 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05547 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05548 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05549 } else {
05550 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05551 }
05552 }
05553
05554 if (!ast_strlen_zero(externnotify)) {
05555 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05556 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05557 } else {
05558 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05559 ast_debug(1, "Executing %s\n", arguments);
05560 ast_safe_system(arguments);
05561 }
05562 }
05563 }
05564
05565
05566
05567
05568
05569
05570 struct leave_vm_options {
05571 unsigned int flags;
05572 signed char record_gain;
05573 char *exitcontext;
05574 };
05575
05576
05577
05578
05579
05580
05581
05582
05583
05584
05585
05586 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05587 {
05588 #ifdef IMAP_STORAGE
05589 int newmsgs, oldmsgs;
05590 #else
05591 char urgdir[PATH_MAX];
05592 #endif
05593 char txtfile[PATH_MAX];
05594 char tmptxtfile[PATH_MAX];
05595 struct vm_state *vms = NULL;
05596 char callerid[256];
05597 FILE *txt;
05598 char date[256];
05599 int txtdes;
05600 int res = 0;
05601 int msgnum;
05602 int duration = 0;
05603 int sound_duration = 0;
05604 int ausemacro = 0;
05605 int ousemacro = 0;
05606 int ouseexten = 0;
05607 char tmpdur[16];
05608 char priority[16];
05609 char origtime[16];
05610 char dir[PATH_MAX];
05611 char tmpdir[PATH_MAX];
05612 char fn[PATH_MAX];
05613 char prefile[PATH_MAX] = "";
05614 char tempfile[PATH_MAX] = "";
05615 char ext_context[256] = "";
05616 char fmt[80];
05617 char *context;
05618 char ecodes[17] = "#";
05619 struct ast_str *tmp = ast_str_create(16);
05620 char *tmpptr;
05621 struct ast_vm_user *vmu;
05622 struct ast_vm_user svm;
05623 const char *category = NULL;
05624 const char *code;
05625 const char *alldtmf = "0123456789ABCD*#";
05626 char flag[80];
05627
05628 if (!tmp) {
05629 return -1;
05630 }
05631
05632 ast_str_set(&tmp, 0, "%s", ext);
05633 ext = ast_str_buffer(tmp);
05634 if ((context = strchr(ext, '@'))) {
05635 *context++ = '\0';
05636 tmpptr = strchr(context, '&');
05637 } else {
05638 tmpptr = strchr(ext, '&');
05639 }
05640
05641 if (tmpptr)
05642 *tmpptr++ = '\0';
05643
05644 ast_channel_lock(chan);
05645 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05646 category = ast_strdupa(category);
05647 }
05648 ast_channel_unlock(chan);
05649
05650 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05651 ast_copy_string(flag, "Urgent", sizeof(flag));
05652 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05653 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05654 } else {
05655 flag[0] = '\0';
05656 }
05657
05658 ast_debug(3, "Before find_user\n");
05659 if (!(vmu = find_user(&svm, context, ext))) {
05660 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05661 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05662 ast_free(tmp);
05663 return res;
05664 }
05665
05666 if (strcmp(vmu->context, "default"))
05667 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05668 else
05669 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05670
05671
05672
05673
05674
05675
05676 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05677 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05678 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05679 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05680 }
05681
05682
05683
05684
05685 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05686 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05687 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05688 ast_free(tmp);
05689 return -1;
05690 }
05691 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05692 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05693 ast_copy_string(prefile, tempfile, sizeof(prefile));
05694
05695 DISPOSE(tempfile, -1);
05696
05697 #ifndef IMAP_STORAGE
05698 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05699 #else
05700 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05701 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05702 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05703 }
05704 #endif
05705
05706
05707 if (ast_test_flag(vmu, VM_OPERATOR)) {
05708 if (!ast_strlen_zero(vmu->exit)) {
05709 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05710 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05711 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05712 ouseexten = 1;
05713 }
05714 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05715 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05716 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05717 ouseexten = 1;
05718 } else if (!ast_strlen_zero(chan->macrocontext)
05719 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05720 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05721 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05722 ousemacro = 1;
05723 }
05724 }
05725
05726 if (!ast_strlen_zero(vmu->exit)) {
05727 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05728 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05729 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05730 }
05731 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05732 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05733 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05734 } else if (!ast_strlen_zero(chan->macrocontext)
05735 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05736 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05737 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05738 ausemacro = 1;
05739 }
05740
05741 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05742 for (code = alldtmf; *code; code++) {
05743 char e[2] = "";
05744 e[0] = *code;
05745 if (strchr(ecodes, e[0]) == NULL
05746 && ast_canmatch_extension(chan,
05747 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05748 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05749 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05750 }
05751 }
05752 }
05753
05754
05755 if (!ast_strlen_zero(prefile)) {
05756 #ifdef ODBC_STORAGE
05757 int success =
05758 #endif
05759 RETRIEVE(prefile, -1, ext, context);
05760 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05761 if (ast_streamfile(chan, prefile, chan->language) > -1)
05762 res = ast_waitstream(chan, ecodes);
05763 #ifdef ODBC_STORAGE
05764 if (success == -1) {
05765
05766 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05767 store_file(prefile, vmu->mailbox, vmu->context, -1);
05768 }
05769 #endif
05770 } else {
05771 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05772 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05773 }
05774 DISPOSE(prefile, -1);
05775 if (res < 0) {
05776 ast_debug(1, "Hang up during prefile playback\n");
05777 free_user(vmu);
05778 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05779 ast_free(tmp);
05780 return -1;
05781 }
05782 }
05783 if (res == '#') {
05784
05785 ast_set_flag(options, OPT_SILENT);
05786 res = 0;
05787 }
05788
05789 if (vmu->maxmsg == 0) {
05790 if (option_debug > 2)
05791 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05792 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05793 goto leave_vm_out;
05794 }
05795 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05796 res = ast_stream_and_wait(chan, INTRO, ecodes);
05797 if (res == '#') {
05798 ast_set_flag(options, OPT_SILENT);
05799 res = 0;
05800 }
05801 }
05802 if (res > 0)
05803 ast_stopstream(chan);
05804
05805
05806 if (res == '*') {
05807 chan->exten[0] = 'a';
05808 chan->exten[1] = '\0';
05809 if (!ast_strlen_zero(vmu->exit)) {
05810 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05811 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05812 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05813 }
05814 chan->priority = 0;
05815 free_user(vmu);
05816 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05817 ast_free(tmp);
05818 return 0;
05819 }
05820
05821
05822 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05823 transfer:
05824 if (ouseexten || ousemacro) {
05825 chan->exten[0] = 'o';
05826 chan->exten[1] = '\0';
05827 if (!ast_strlen_zero(vmu->exit)) {
05828 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05829 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05830 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05831 }
05832 ast_play_and_wait(chan, "transfer");
05833 chan->priority = 0;
05834 free_user(vmu);
05835 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05836 }
05837 ast_free(tmp);
05838 return OPERATOR_EXIT;
05839 }
05840
05841
05842 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05843 if (!ast_strlen_zero(options->exitcontext)) {
05844 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05845 }
05846 free_user(vmu);
05847 ast_free(tmp);
05848 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05849 return res;
05850 }
05851
05852 if (res < 0) {
05853 free_user(vmu);
05854 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05855 ast_free(tmp);
05856 return -1;
05857 }
05858
05859 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05860 if (!ast_strlen_zero(fmt)) {
05861 msgnum = 0;
05862
05863 #ifdef IMAP_STORAGE
05864
05865
05866 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05867 if (res < 0) {
05868 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05869 ast_free(tmp);
05870 return -1;
05871 }
05872 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05873
05874
05875
05876
05877 if (!(vms = create_vm_state_from_user(vmu))) {
05878 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05879 ast_free(tmp);
05880 return -1;
05881 }
05882 }
05883 vms->newmessages++;
05884
05885
05886 msgnum = newmsgs + oldmsgs;
05887 ast_debug(3, "Messagecount set to %d\n", msgnum);
05888 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05889
05890 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05891
05892 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05893 goto leave_vm_out;
05894 }
05895 #else
05896 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05897 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05898 if (!res)
05899 res = ast_waitstream(chan, "");
05900 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05901 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05902 inprocess_count(vmu->mailbox, vmu->context, -1);
05903 goto leave_vm_out;
05904 }
05905
05906 #endif
05907 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05908 txtdes = mkstemp(tmptxtfile);
05909 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05910 if (txtdes < 0) {
05911 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05912 if (!res)
05913 res = ast_waitstream(chan, "");
05914 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05915 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05916 inprocess_count(vmu->mailbox, vmu->context, -1);
05917 goto leave_vm_out;
05918 }
05919
05920
05921 if (res >= 0) {
05922
05923 res = ast_stream_and_wait(chan, "beep", "");
05924 }
05925
05926
05927 if (ast_check_realtime("voicemail_data")) {
05928 snprintf(priority, sizeof(priority), "%d", chan->priority);
05929 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05930 get_date(date, sizeof(date));
05931 ast_callerid_merge(callerid, sizeof(callerid),
05932 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05933 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05934 "Unknown");
05935 ast_store_realtime("voicemail_data",
05936 "origmailbox", ext,
05937 "context", chan->context,
05938 "macrocontext", chan->macrocontext,
05939 "exten", chan->exten,
05940 "priority", priority,
05941 "callerchan", chan->name,
05942 "callerid", callerid,
05943 "origdate", date,
05944 "origtime", origtime,
05945 "category", S_OR(category, ""),
05946 "filename", tmptxtfile,
05947 SENTINEL);
05948 }
05949
05950
05951 txt = fdopen(txtdes, "w+");
05952 if (txt) {
05953 get_date(date, sizeof(date));
05954 ast_callerid_merge(callerid, sizeof(callerid),
05955 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05956 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05957 "Unknown");
05958 fprintf(txt,
05959 ";\n"
05960 "; Message Information file\n"
05961 ";\n"
05962 "[message]\n"
05963 "origmailbox=%s\n"
05964 "context=%s\n"
05965 "macrocontext=%s\n"
05966 "exten=%s\n"
05967 "rdnis=%s\n"
05968 "priority=%d\n"
05969 "callerchan=%s\n"
05970 "callerid=%s\n"
05971 "origdate=%s\n"
05972 "origtime=%ld\n"
05973 "category=%s\n",
05974 ext,
05975 chan->context,
05976 chan->macrocontext,
05977 chan->exten,
05978 S_COR(chan->redirecting.from.number.valid,
05979 chan->redirecting.from.number.str, "unknown"),
05980 chan->priority,
05981 chan->name,
05982 callerid,
05983 date, (long) time(NULL),
05984 category ? category : "");
05985 } else {
05986 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05987 inprocess_count(vmu->mailbox, vmu->context, -1);
05988 if (ast_check_realtime("voicemail_data")) {
05989 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05990 }
05991 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05992 goto leave_vm_out;
05993 }
05994 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
05995
05996 if (txt) {
05997 fprintf(txt, "flag=%s\n", flag);
05998 if (sound_duration < vmu->minsecs) {
05999 fclose(txt);
06000 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06001 ast_filedelete(tmptxtfile, NULL);
06002 unlink(tmptxtfile);
06003 if (ast_check_realtime("voicemail_data")) {
06004 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06005 }
06006 inprocess_count(vmu->mailbox, vmu->context, -1);
06007 } else {
06008 fprintf(txt, "duration=%d\n", duration);
06009 fclose(txt);
06010 if (vm_lock_path(dir)) {
06011 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06012
06013 ast_filedelete(tmptxtfile, NULL);
06014 unlink(tmptxtfile);
06015 inprocess_count(vmu->mailbox, vmu->context, -1);
06016 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06017 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06018 unlink(tmptxtfile);
06019 ast_unlock_path(dir);
06020 inprocess_count(vmu->mailbox, vmu->context, -1);
06021 if (ast_check_realtime("voicemail_data")) {
06022 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06023 }
06024 } else {
06025 #ifndef IMAP_STORAGE
06026 msgnum = last_message_index(vmu, dir) + 1;
06027 #endif
06028 make_file(fn, sizeof(fn), dir, msgnum);
06029
06030
06031 #ifndef IMAP_STORAGE
06032 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06033 #else
06034 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06035 #endif
06036
06037 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06038 ast_filerename(tmptxtfile, fn, NULL);
06039 rename(tmptxtfile, txtfile);
06040 inprocess_count(vmu->mailbox, vmu->context, -1);
06041
06042
06043
06044 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06045 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06046
06047 ast_unlock_path(dir);
06048 if (ast_check_realtime("voicemail_data")) {
06049 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06050 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06051 }
06052
06053
06054
06055 if (ast_fileexists(fn, NULL, NULL) > 0) {
06056 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06057 }
06058
06059
06060 while (tmpptr) {
06061 struct ast_vm_user recipu, *recip;
06062 char *exten, *cntx;
06063
06064 exten = strsep(&tmpptr, "&");
06065 cntx = strchr(exten, '@');
06066 if (cntx) {
06067 *cntx = '\0';
06068 cntx++;
06069 }
06070 if ((recip = find_user(&recipu, cntx, exten))) {
06071 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06072 free_user(recip);
06073 }
06074 }
06075 #ifndef IMAP_STORAGE
06076 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06077
06078 char sfn[PATH_MAX];
06079 char dfn[PATH_MAX];
06080 int x;
06081
06082 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06083 x = last_message_index(vmu, urgdir) + 1;
06084 make_file(sfn, sizeof(sfn), dir, msgnum);
06085 make_file(dfn, sizeof(dfn), urgdir, x);
06086 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06087 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06088
06089 ast_copy_string(fn, dfn, sizeof(fn));
06090 msgnum = x;
06091 }
06092 #endif
06093
06094 if (ast_fileexists(fn, NULL, NULL)) {
06095 #ifdef IMAP_STORAGE
06096 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06097 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06098 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06099 flag);
06100 #else
06101 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06102 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06103 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06104 flag);
06105 #endif
06106 }
06107
06108
06109 if (ast_fileexists(fn, NULL, NULL)) {
06110 DISPOSE(dir, msgnum);
06111 }
06112 }
06113 }
06114 } else {
06115 inprocess_count(vmu->mailbox, vmu->context, -1);
06116 }
06117 if (res == '0') {
06118 goto transfer;
06119 } else if (res > 0 && res != 't')
06120 res = 0;
06121
06122 if (sound_duration < vmu->minsecs)
06123
06124 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06125 else
06126 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06127 } else
06128 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06129 leave_vm_out:
06130 free_user(vmu);
06131
06132 #ifdef IMAP_STORAGE
06133
06134 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06135 if (expungeonhangup == 1) {
06136 ast_mutex_lock(&vms->lock);
06137 #ifdef HAVE_IMAP_TK2006
06138 if (LEVELUIDPLUS (vms->mailstream)) {
06139 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06140 } else
06141 #endif
06142 mail_expunge(vms->mailstream);
06143 ast_mutex_unlock(&vms->lock);
06144 }
06145 #endif
06146
06147 ast_free(tmp);
06148 return res;
06149 }
06150
06151 #if !defined(IMAP_STORAGE)
06152 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06153 {
06154
06155
06156 int x, dest;
06157 char sfn[PATH_MAX];
06158 char dfn[PATH_MAX];
06159
06160 if (vm_lock_path(dir)) {
06161 return ERROR_LOCK_PATH;
06162 }
06163
06164 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06165 make_file(sfn, sizeof(sfn), dir, x);
06166 if (EXISTS(dir, x, sfn, NULL)) {
06167
06168 if (x != dest) {
06169 make_file(dfn, sizeof(dfn), dir, dest);
06170 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06171 }
06172
06173 dest++;
06174 }
06175 }
06176 ast_unlock_path(dir);
06177
06178 return dest;
06179 }
06180 #endif
06181
06182 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06183 {
06184 int d;
06185 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06186 return d;
06187 }
06188
06189 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06190 {
06191 #ifdef IMAP_STORAGE
06192
06193
06194 char sequence[10];
06195 char mailbox[256];
06196 int res;
06197
06198
06199 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06200
06201 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06202 ast_mutex_lock(&vms->lock);
06203
06204 if (box == OLD_FOLDER) {
06205 mail_setflag(vms->mailstream, sequence, "\\Seen");
06206 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06207 } else if (box == NEW_FOLDER) {
06208 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06209 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06210 }
06211 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06212 ast_mutex_unlock(&vms->lock);
06213 return 0;
06214 }
06215
06216 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06217 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06218 if (mail_create(vms->mailstream, mailbox) == NIL)
06219 ast_debug(5, "Folder exists.\n");
06220 else
06221 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06222 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06223 ast_mutex_unlock(&vms->lock);
06224 return res;
06225 #else
06226 char *dir = vms->curdir;
06227 char *username = vms->username;
06228 char *context = vmu->context;
06229 char sfn[PATH_MAX];
06230 char dfn[PATH_MAX];
06231 char ddir[PATH_MAX];
06232 const char *dbox = mbox(vmu, box);
06233 int x, i;
06234 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06235
06236 if (vm_lock_path(ddir))
06237 return ERROR_LOCK_PATH;
06238
06239 x = last_message_index(vmu, ddir) + 1;
06240
06241 if (box == 10 && x >= vmu->maxdeletedmsg) {
06242 x--;
06243 for (i = 1; i <= x; i++) {
06244
06245 make_file(sfn, sizeof(sfn), ddir, i);
06246 make_file(dfn, sizeof(dfn), ddir, i - 1);
06247 if (EXISTS(ddir, i, sfn, NULL)) {
06248 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06249 } else
06250 break;
06251 }
06252 } else {
06253 if (x >= vmu->maxmsg) {
06254 ast_unlock_path(ddir);
06255 return -1;
06256 }
06257 }
06258 make_file(sfn, sizeof(sfn), dir, msg);
06259 make_file(dfn, sizeof(dfn), ddir, x);
06260 if (strcmp(sfn, dfn)) {
06261 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06262 }
06263 ast_unlock_path(ddir);
06264 #endif
06265 return 0;
06266 }
06267
06268 static int adsi_logo(unsigned char *buf)
06269 {
06270 int bytes = 0;
06271 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06272 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06273 return bytes;
06274 }
06275
06276 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06277 {
06278 unsigned char buf[256];
06279 int bytes = 0;
06280 int x;
06281 char num[5];
06282
06283 *useadsi = 0;
06284 bytes += ast_adsi_data_mode(buf + bytes);
06285 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06286
06287 bytes = 0;
06288 bytes += adsi_logo(buf);
06289 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06290 #ifdef DISPLAY
06291 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06292 #endif
06293 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06294 bytes += ast_adsi_data_mode(buf + bytes);
06295 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06296
06297 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06298 bytes = 0;
06299 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06300 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06301 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06302 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06303 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06304 return 0;
06305 }
06306
06307 #ifdef DISPLAY
06308
06309 bytes = 0;
06310 bytes += ast_adsi_logo(buf);
06311 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06312 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06313 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06314 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06315 #endif
06316 bytes = 0;
06317 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06318 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06319 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06320 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06321 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06322 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06323 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06324
06325 #ifdef DISPLAY
06326
06327 bytes = 0;
06328 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06329 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06330
06331 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06332 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06333 #endif
06334
06335 bytes = 0;
06336
06337 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06338 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06339 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06340 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06341 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06342 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06343 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06344
06345 #ifdef DISPLAY
06346
06347 bytes = 0;
06348 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06349 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06350 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06351 #endif
06352
06353 bytes = 0;
06354 for (x = 0; x < 5; x++) {
06355 snprintf(num, sizeof(num), "%d", x);
06356 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06357 }
06358 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06359 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06360
06361 #ifdef DISPLAY
06362
06363 bytes = 0;
06364 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06365 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06366 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06367 #endif
06368
06369 if (ast_adsi_end_download(chan)) {
06370 bytes = 0;
06371 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06372 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06373 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06374 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06375 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06376 return 0;
06377 }
06378 bytes = 0;
06379 bytes += ast_adsi_download_disconnect(buf + bytes);
06380 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06381 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06382
06383 ast_debug(1, "Done downloading scripts...\n");
06384
06385 #ifdef DISPLAY
06386
06387 bytes = 0;
06388 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06389 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06390 #endif
06391 ast_debug(1, "Restarting session...\n");
06392
06393 bytes = 0;
06394
06395 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06396 *useadsi = 1;
06397 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06398 } else
06399 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06400
06401 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06402 return 0;
06403 }
06404
06405 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06406 {
06407 int x;
06408 if (!ast_adsi_available(chan))
06409 return;
06410 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06411 if (x < 0)
06412 return;
06413 if (!x) {
06414 if (adsi_load_vmail(chan, useadsi)) {
06415 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06416 return;
06417 }
06418 } else
06419 *useadsi = 1;
06420 }
06421
06422 static void adsi_login(struct ast_channel *chan)
06423 {
06424 unsigned char buf[256];
06425 int bytes = 0;
06426 unsigned char keys[8];
06427 int x;
06428 if (!ast_adsi_available(chan))
06429 return;
06430
06431 for (x = 0; x < 8; x++)
06432 keys[x] = 0;
06433
06434 keys[3] = ADSI_KEY_APPS + 3;
06435
06436 bytes += adsi_logo(buf + bytes);
06437 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06438 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06439 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06440 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06441 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06442 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06443 bytes += ast_adsi_set_keys(buf + bytes, keys);
06444 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06445 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06446 }
06447
06448 static void adsi_password(struct ast_channel *chan)
06449 {
06450 unsigned char buf[256];
06451 int bytes = 0;
06452 unsigned char keys[8];
06453 int x;
06454 if (!ast_adsi_available(chan))
06455 return;
06456
06457 for (x = 0; x < 8; x++)
06458 keys[x] = 0;
06459
06460 keys[3] = ADSI_KEY_APPS + 3;
06461
06462 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06463 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06464 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06465 bytes += ast_adsi_set_keys(buf + bytes, keys);
06466 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06467 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06468 }
06469
06470 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06471 {
06472 unsigned char buf[256];
06473 int bytes = 0;
06474 unsigned char keys[8];
06475 int x, y;
06476
06477 if (!ast_adsi_available(chan))
06478 return;
06479
06480 for (x = 0; x < 5; x++) {
06481 y = ADSI_KEY_APPS + 12 + start + x;
06482 if (y > ADSI_KEY_APPS + 12 + 4)
06483 y = 0;
06484 keys[x] = ADSI_KEY_SKT | y;
06485 }
06486 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06487 keys[6] = 0;
06488 keys[7] = 0;
06489
06490 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06491 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06492 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06493 bytes += ast_adsi_set_keys(buf + bytes, keys);
06494 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06495
06496 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06497 }
06498
06499 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06500 {
06501 int bytes = 0;
06502 unsigned char buf[256];
06503 char buf1[256], buf2[256];
06504 char fn2[PATH_MAX];
06505
06506 char cid[256] = "";
06507 char *val;
06508 char *name, *num;
06509 char datetime[21] = "";
06510 FILE *f;
06511
06512 unsigned char keys[8];
06513
06514 int x;
06515
06516 if (!ast_adsi_available(chan))
06517 return;
06518
06519
06520 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06521 f = fopen(fn2, "r");
06522 if (f) {
06523 while (!feof(f)) {
06524 if (!fgets((char *) buf, sizeof(buf), f)) {
06525 continue;
06526 }
06527 if (!feof(f)) {
06528 char *stringp = NULL;
06529 stringp = (char *) buf;
06530 strsep(&stringp, "=");
06531 val = strsep(&stringp, "=");
06532 if (!ast_strlen_zero(val)) {
06533 if (!strcmp((char *) buf, "callerid"))
06534 ast_copy_string(cid, val, sizeof(cid));
06535 if (!strcmp((char *) buf, "origdate"))
06536 ast_copy_string(datetime, val, sizeof(datetime));
06537 }
06538 }
06539 }
06540 fclose(f);
06541 }
06542
06543 for (x = 0; x < 5; x++)
06544 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06545 keys[6] = 0x0;
06546 keys[7] = 0x0;
06547
06548 if (!vms->curmsg) {
06549
06550 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06551 }
06552 if (vms->curmsg >= vms->lastmsg) {
06553
06554 if (vms->curmsg) {
06555
06556 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06557 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06558
06559 } else {
06560
06561 keys[3] = 1;
06562 }
06563 }
06564
06565 if (!ast_strlen_zero(cid)) {
06566 ast_callerid_parse(cid, &name, &num);
06567 if (!name)
06568 name = num;
06569 } else
06570 name = "Unknown Caller";
06571
06572
06573 #ifdef IMAP_STORAGE
06574 ast_mutex_lock(&vms->lock);
06575 #endif
06576 if (vms->deleted[vms->curmsg]) {
06577 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06578 }
06579 #ifdef IMAP_STORAGE
06580 ast_mutex_unlock(&vms->lock);
06581 #endif
06582
06583
06584 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06585 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06586 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06587 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06588
06589 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06590 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06591 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06592 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06593 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06594 bytes += ast_adsi_set_keys(buf + bytes, keys);
06595 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06596
06597 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06598 }
06599
06600 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06601 {
06602 int bytes = 0;
06603 unsigned char buf[256];
06604 unsigned char keys[8];
06605
06606 int x;
06607
06608 if (!ast_adsi_available(chan))
06609 return;
06610
06611
06612 for (x = 0; x < 5; x++)
06613 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06614
06615 keys[6] = 0x0;
06616 keys[7] = 0x0;
06617
06618 if (!vms->curmsg) {
06619
06620 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06621 }
06622 if (vms->curmsg >= vms->lastmsg) {
06623
06624 if (vms->curmsg) {
06625
06626 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06627 } else {
06628
06629 keys[3] = 1;
06630 }
06631 }
06632
06633
06634 #ifdef IMAP_STORAGE
06635 ast_mutex_lock(&vms->lock);
06636 #endif
06637 if (vms->deleted[vms->curmsg]) {
06638 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06639 }
06640 #ifdef IMAP_STORAGE
06641 ast_mutex_unlock(&vms->lock);
06642 #endif
06643
06644
06645 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06646 bytes += ast_adsi_set_keys(buf + bytes, keys);
06647 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06648
06649 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06650 }
06651
06652 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06653 {
06654 unsigned char buf[256] = "";
06655 char buf1[256] = "", buf2[256] = "";
06656 int bytes = 0;
06657 unsigned char keys[8];
06658 int x;
06659
06660 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06661 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06662 if (!ast_adsi_available(chan))
06663 return;
06664 if (vms->newmessages) {
06665 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06666 if (vms->oldmessages) {
06667 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06668 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06669 } else {
06670 snprintf(buf2, sizeof(buf2), "%s.", newm);
06671 }
06672 } else if (vms->oldmessages) {
06673 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06674 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06675 } else {
06676 strcpy(buf1, "You have no messages.");
06677 buf2[0] = ' ';
06678 buf2[1] = '\0';
06679 }
06680 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06681 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06682 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06683
06684 for (x = 0; x < 6; x++)
06685 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06686 keys[6] = 0;
06687 keys[7] = 0;
06688
06689
06690 if (vms->lastmsg < 0)
06691 keys[0] = 1;
06692 bytes += ast_adsi_set_keys(buf + bytes, keys);
06693
06694 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06695
06696 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06697 }
06698
06699 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06700 {
06701 unsigned char buf[256] = "";
06702 char buf1[256] = "", buf2[256] = "";
06703 int bytes = 0;
06704 unsigned char keys[8];
06705 int x;
06706
06707 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06708
06709 if (!ast_adsi_available(chan))
06710 return;
06711
06712
06713 for (x = 0; x < 6; x++)
06714 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06715
06716 keys[6] = 0;
06717 keys[7] = 0;
06718
06719 if ((vms->lastmsg + 1) < 1)
06720 keys[0] = 0;
06721
06722 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06723 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06724
06725 if (vms->lastmsg + 1)
06726 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06727 else
06728 strcpy(buf2, "no messages.");
06729 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06730 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06731 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06732 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06733 bytes += ast_adsi_set_keys(buf + bytes, keys);
06734
06735 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06736
06737 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06738
06739 }
06740
06741
06742
06743
06744
06745
06746
06747
06748
06749
06750
06751
06752
06753
06754
06755 static void adsi_goodbye(struct ast_channel *chan)
06756 {
06757 unsigned char buf[256];
06758 int bytes = 0;
06759
06760 if (!ast_adsi_available(chan))
06761 return;
06762 bytes += adsi_logo(buf + bytes);
06763 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06764 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06765 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06766 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06767
06768 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06769 }
06770
06771
06772
06773
06774
06775 static int get_folder(struct ast_channel *chan, int start)
06776 {
06777 int x;
06778 int d;
06779 char fn[PATH_MAX];
06780 d = ast_play_and_wait(chan, "vm-press");
06781 if (d)
06782 return d;
06783 for (x = start; x < 5; x++) {
06784 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06785 return d;
06786 d = ast_play_and_wait(chan, "vm-for");
06787 if (d)
06788 return d;
06789 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06790
06791
06792
06793
06794 if (x == 0) {
06795 if (ast_fileexists(fn, NULL, NULL)) {
06796 d = vm_play_folder_name(chan, fn);
06797 } else {
06798 ast_verb(1, "failed to find %s\n", fn);
06799 d = vm_play_folder_name(chan, "vm-INBOX");
06800 }
06801 } else {
06802 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06803 d = vm_play_folder_name(chan, fn);
06804 }
06805
06806 if (d)
06807 return d;
06808 d = ast_waitfordigit(chan, 500);
06809 if (d)
06810 return d;
06811 }
06812
06813 d = ast_play_and_wait(chan, "vm-tocancel");
06814 if (d)
06815 return d;
06816 d = ast_waitfordigit(chan, 4000);
06817 return d;
06818 }
06819
06820
06821
06822
06823
06824
06825
06826
06827
06828
06829
06830
06831
06832 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06833 {
06834 int res = 0;
06835 int loops = 0;
06836
06837 res = ast_play_and_wait(chan, fn);
06838 while (((res < '0') || (res > '9')) &&
06839 (res != '#') && (res >= 0) &&
06840 loops < 4) {
06841 res = get_folder(chan, 0);
06842 loops++;
06843 }
06844 if (loops == 4) {
06845 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06846 return '#';
06847 }
06848 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06849 return res;
06850 }
06851
06852
06853
06854
06855
06856
06857
06858
06859
06860
06861
06862
06863
06864
06865
06866
06867
06868
06869
06870 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06871 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06872 {
06873 int cmd = 0;
06874 int retries = 0, prepend_duration = 0, already_recorded = 0;
06875 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06876 char textfile[PATH_MAX];
06877 struct ast_config *msg_cfg;
06878 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06879 #ifndef IMAP_STORAGE
06880 signed char zero_gain = 0;
06881 #endif
06882 const char *duration_str;
06883
06884
06885 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06886 strcpy(textfile, msgfile);
06887 strcpy(backup, msgfile);
06888 strcpy(backup_textfile, msgfile);
06889 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06890 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06891 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06892
06893 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06894 *duration = atoi(duration_str);
06895 } else {
06896 *duration = 0;
06897 }
06898
06899 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06900 if (cmd)
06901 retries = 0;
06902 switch (cmd) {
06903 case '1':
06904
06905 #ifdef IMAP_STORAGE
06906
06907 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06908 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06909 ast_play_and_wait(chan, INTRO);
06910 ast_play_and_wait(chan, "beep");
06911 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06912 if (cmd == -1) {
06913 break;
06914 }
06915 cmd = 't';
06916 #else
06917
06918
06919
06920 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06921 strcpy(textfile, msgfile);
06922 strncat(textfile, ".txt", sizeof(textfile) - 1);
06923 *duration = 0;
06924
06925
06926 if (!msg_cfg) {
06927 cmd = 0;
06928 break;
06929 }
06930
06931
06932 #ifndef IMAP_STORAGE
06933 if (already_recorded) {
06934 ast_filecopy(backup, msgfile, NULL);
06935 copy(backup_textfile, textfile);
06936 }
06937 else {
06938 ast_filecopy(msgfile, backup, NULL);
06939 copy(textfile, backup_textfile);
06940 }
06941 #endif
06942 already_recorded = 1;
06943
06944 if (record_gain)
06945 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06946
06947 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06948
06949 if (cmd == 'S') {
06950 ast_stream_and_wait(chan, vm_pls_try_again, "");
06951 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06952 ast_filerename(backup, msgfile, NULL);
06953 }
06954
06955 if (record_gain)
06956 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06957
06958
06959 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06960 *duration = atoi(duration_str);
06961
06962 if (prepend_duration) {
06963 struct ast_category *msg_cat;
06964
06965 char duration_buf[12];
06966
06967 *duration += prepend_duration;
06968 msg_cat = ast_category_get(msg_cfg, "message");
06969 snprintf(duration_buf, 11, "%ld", *duration);
06970 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06971 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06972 }
06973 }
06974
06975 #endif
06976 break;
06977 case '2':
06978
06979 #ifdef IMAP_STORAGE
06980 *vms->introfn = '\0';
06981 #endif
06982 cmd = 't';
06983 break;
06984 case '*':
06985 cmd = '*';
06986 break;
06987 default:
06988
06989 already_recorded = 0;
06990
06991 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06992
06993 if (!cmd) {
06994 cmd = ast_play_and_wait(chan, "vm-starmain");
06995
06996 }
06997 if (!cmd) {
06998 cmd = ast_waitfordigit(chan, 6000);
06999 }
07000 if (!cmd) {
07001 retries++;
07002 }
07003 if (retries > 3) {
07004 cmd = '*';
07005 }
07006 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07007 }
07008 }
07009
07010 if (msg_cfg)
07011 ast_config_destroy(msg_cfg);
07012 if (prepend_duration)
07013 *duration = prepend_duration;
07014
07015 if (already_recorded && cmd == -1) {
07016
07017 ast_filerename(backup, msgfile, NULL);
07018 rename(backup_textfile, textfile);
07019 }
07020
07021 if (cmd == 't' || cmd == 'S')
07022 cmd = 0;
07023 return cmd;
07024 }
07025
07026 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07027 {
07028 struct ast_event *event;
07029 char *mailbox, *context;
07030
07031
07032 context = mailbox = ast_strdupa(box);
07033 strsep(&context, "@");
07034 if (ast_strlen_zero(context))
07035 context = "default";
07036
07037 if (!(event = ast_event_new(AST_EVENT_MWI,
07038 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07039 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07040 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07041 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07042 AST_EVENT_IE_END))) {
07043 return;
07044 }
07045
07046 ast_event_queue_and_cache(event);
07047 }
07048
07049
07050
07051
07052
07053
07054
07055
07056
07057
07058
07059
07060
07061
07062
07063 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)
07064 {
07065 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07066 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07067 const char *category;
07068 char *myserveremail = serveremail;
07069
07070 ast_channel_lock(chan);
07071 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07072 category = ast_strdupa(category);
07073 }
07074 ast_channel_unlock(chan);
07075
07076 #ifndef IMAP_STORAGE
07077 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07078 #else
07079 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07080 #endif
07081 make_file(fn, sizeof(fn), todir, msgnum);
07082 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07083
07084 if (!ast_strlen_zero(vmu->attachfmt)) {
07085 if (strstr(fmt, vmu->attachfmt))
07086 fmt = vmu->attachfmt;
07087 else
07088 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);
07089 }
07090
07091
07092 fmt = ast_strdupa(fmt);
07093 stringp = fmt;
07094 strsep(&stringp, "|");
07095
07096 if (!ast_strlen_zero(vmu->serveremail))
07097 myserveremail = vmu->serveremail;
07098
07099 if (!ast_strlen_zero(vmu->email)) {
07100 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07101
07102 if (attach_user_voicemail)
07103 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07104
07105
07106 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07107
07108 if (attach_user_voicemail)
07109 DISPOSE(todir, msgnum);
07110 }
07111
07112 if (!ast_strlen_zero(vmu->pager)) {
07113 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07114 }
07115
07116 if (ast_test_flag(vmu, VM_DELETE))
07117 DELETE(todir, msgnum, fn, vmu);
07118
07119
07120 if (ast_app_has_voicemail(ext_context, NULL))
07121 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07122
07123 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07124
07125 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);
07126 run_externnotify(vmu->context, vmu->mailbox, flag);
07127
07128 #ifdef IMAP_STORAGE
07129 vm_delete(fn);
07130 if (ast_test_flag(vmu, VM_DELETE)) {
07131 vm_imap_delete(NULL, vms->curmsg, vmu);
07132 vms->newmessages--;
07133 }
07134 #endif
07135
07136 return 0;
07137 }
07138
07139
07140
07141
07142
07143
07144
07145
07146
07147
07148
07149
07150
07151
07152
07153
07154
07155
07156
07157
07158
07159
07160
07161
07162
07163
07164
07165
07166 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)
07167 {
07168 #ifdef IMAP_STORAGE
07169 int todircount = 0;
07170 struct vm_state *dstvms;
07171 #endif
07172 char username[70]="";
07173 char fn[PATH_MAX];
07174 char ecodes[16] = "#";
07175 int res = 0, cmd = 0;
07176 struct ast_vm_user *receiver = NULL, *vmtmp;
07177 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07178 char *stringp;
07179 const char *s;
07180 int saved_messages = 0;
07181 int valid_extensions = 0;
07182 char *dir;
07183 int curmsg;
07184 char urgent_str[7] = "";
07185 int prompt_played = 0;
07186 #ifndef IMAP_STORAGE
07187 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07188 #endif
07189 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07190 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07191 }
07192
07193 if (vms == NULL) return -1;
07194 dir = vms->curdir;
07195 curmsg = vms->curmsg;
07196
07197 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07198 while (!res && !valid_extensions) {
07199 int use_directory = 0;
07200 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07201 int done = 0;
07202 int retries = 0;
07203 cmd = 0;
07204 while ((cmd >= 0) && !done ){
07205 if (cmd)
07206 retries = 0;
07207 switch (cmd) {
07208 case '1':
07209 use_directory = 0;
07210 done = 1;
07211 break;
07212 case '2':
07213 use_directory = 1;
07214 done = 1;
07215 break;
07216 case '*':
07217 cmd = 't';
07218 done = 1;
07219 break;
07220 default:
07221
07222 cmd = ast_play_and_wait(chan, "vm-forward");
07223 if (!cmd) {
07224 cmd = ast_waitfordigit(chan, 3000);
07225 }
07226 if (!cmd) {
07227 retries++;
07228 }
07229 if (retries > 3) {
07230 cmd = 't';
07231 done = 1;
07232 }
07233 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07234 }
07235 }
07236 if (cmd < 0 || cmd == 't')
07237 break;
07238 }
07239
07240 if (use_directory) {
07241
07242
07243 char old_context[sizeof(chan->context)];
07244 char old_exten[sizeof(chan->exten)];
07245 int old_priority;
07246 struct ast_app* directory_app;
07247
07248 directory_app = pbx_findapp("Directory");
07249 if (directory_app) {
07250 char vmcontext[256];
07251
07252 memcpy(old_context, chan->context, sizeof(chan->context));
07253 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07254 old_priority = chan->priority;
07255
07256
07257 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07258 res = pbx_exec(chan, directory_app, vmcontext);
07259
07260 ast_copy_string(username, chan->exten, sizeof(username));
07261
07262
07263 memcpy(chan->context, old_context, sizeof(chan->context));
07264 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07265 chan->priority = old_priority;
07266 } else {
07267 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07268 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07269 }
07270 } else {
07271
07272 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07273 res = ast_streamfile(chan, "vm-extension", chan->language);
07274 prompt_played++;
07275 if (res || prompt_played > 4)
07276 break;
07277 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07278 break;
07279 }
07280
07281
07282 if (ast_strlen_zero(username))
07283 continue;
07284 stringp = username;
07285 s = strsep(&stringp, "*");
07286
07287 valid_extensions = 1;
07288 while (s) {
07289 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07290 int oldmsgs;
07291 int newmsgs;
07292 int capacity;
07293 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07294 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07295
07296 res = ast_play_and_wait(chan, "pbx-invalid");
07297 valid_extensions = 0;
07298 break;
07299 }
07300 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07301 if ((newmsgs + oldmsgs) >= capacity) {
07302 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07303 res = ast_play_and_wait(chan, "vm-mailboxfull");
07304 valid_extensions = 0;
07305 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07306 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07307 free_user(vmtmp);
07308 }
07309 inprocess_count(receiver->mailbox, receiver->context, -1);
07310 break;
07311 }
07312 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07313 } else {
07314
07315
07316
07317
07318
07319 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07320 free_user(receiver);
07321 }
07322 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07323
07324 res = ast_play_and_wait(chan, "pbx-invalid");
07325 valid_extensions = 0;
07326 break;
07327 }
07328
07329
07330 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07331 RETRIEVE(fn, -1, s, receiver->context);
07332 if (ast_fileexists(fn, NULL, NULL) > 0) {
07333 res = ast_stream_and_wait(chan, fn, ecodes);
07334 if (res) {
07335 DISPOSE(fn, -1);
07336 return res;
07337 }
07338 } else {
07339 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07340 }
07341 DISPOSE(fn, -1);
07342
07343 s = strsep(&stringp, "*");
07344 }
07345
07346 if (valid_extensions)
07347 break;
07348 }
07349
07350 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07351 return res;
07352 if (is_new_message == 1) {
07353 struct leave_vm_options leave_options;
07354 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07355 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07356
07357
07358 memset(&leave_options, 0, sizeof(leave_options));
07359 leave_options.record_gain = record_gain;
07360 cmd = leave_voicemail(chan, mailbox, &leave_options);
07361 } else {
07362
07363 long duration = 0;
07364 struct vm_state vmstmp;
07365 int copy_msg_result = 0;
07366 memcpy(&vmstmp, vms, sizeof(vmstmp));
07367
07368 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07369
07370 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07371 if (!cmd) {
07372 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07373 #ifdef IMAP_STORAGE
07374 int attach_user_voicemail;
07375 char *myserveremail = serveremail;
07376
07377
07378 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07379 if (!dstvms) {
07380 dstvms = create_vm_state_from_user(vmtmp);
07381 }
07382 if (dstvms) {
07383 init_mailstream(dstvms, 0);
07384 if (!dstvms->mailstream) {
07385 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07386 } else {
07387 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07388 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07389 }
07390 } else {
07391 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07392 }
07393 if (!ast_strlen_zero(vmtmp->serveremail))
07394 myserveremail = vmtmp->serveremail;
07395 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07396
07397 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07398 dstvms->curbox,
07399 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07400 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07401 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07402 NULL, urgent_str);
07403 #else
07404 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07405 #endif
07406 saved_messages++;
07407 AST_LIST_REMOVE_CURRENT(list);
07408 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07409 free_user(vmtmp);
07410 if (res)
07411 break;
07412 }
07413 AST_LIST_TRAVERSE_SAFE_END;
07414 if (saved_messages > 0 && !copy_msg_result) {
07415
07416
07417
07418
07419
07420
07421
07422
07423 #ifdef IMAP_STORAGE
07424
07425 if (ast_strlen_zero(vmstmp.introfn))
07426 #endif
07427 res = ast_play_and_wait(chan, "vm-msgsaved");
07428 }
07429 #ifndef IMAP_STORAGE
07430 else {
07431
07432 res = ast_play_and_wait(chan, "vm-mailboxfull");
07433 }
07434
07435 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07436 strcpy(textfile, msgfile);
07437 strcpy(backup, msgfile);
07438 strcpy(backup_textfile, msgfile);
07439 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07440 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07441 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07442 if (ast_fileexists(backup, NULL, NULL) > 0) {
07443 ast_filerename(backup, msgfile, NULL);
07444 rename(backup_textfile, textfile);
07445 }
07446 #endif
07447 }
07448 DISPOSE(dir, curmsg);
07449 #ifndef IMAP_STORAGE
07450 if (cmd) {
07451 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07452 strcpy(textfile, msgfile);
07453 strcpy(backup_textfile, msgfile);
07454 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07455 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07456 rename(backup_textfile, textfile);
07457 }
07458 #endif
07459 }
07460
07461
07462 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07463 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07464 free_user(vmtmp);
07465 }
07466 return res ? res : cmd;
07467 }
07468
07469 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07470 {
07471 int res;
07472 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07473 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07474 return res;
07475 }
07476
07477 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07478 {
07479 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07480 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);
07481 }
07482
07483 static int play_message_category(struct ast_channel *chan, const char *category)
07484 {
07485 int res = 0;
07486
07487 if (!ast_strlen_zero(category))
07488 res = ast_play_and_wait(chan, category);
07489
07490 if (res) {
07491 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07492 res = 0;
07493 }
07494
07495 return res;
07496 }
07497
07498 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07499 {
07500 int res = 0;
07501 struct vm_zone *the_zone = NULL;
07502 time_t t;
07503
07504 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07505 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07506 return 0;
07507 }
07508
07509
07510 if (!ast_strlen_zero(vmu->zonetag)) {
07511
07512 struct vm_zone *z;
07513 AST_LIST_LOCK(&zones);
07514 AST_LIST_TRAVERSE(&zones, z, list) {
07515 if (!strcmp(z->name, vmu->zonetag)) {
07516 the_zone = z;
07517 break;
07518 }
07519 }
07520 AST_LIST_UNLOCK(&zones);
07521 }
07522
07523
07524 #if 0
07525
07526 ast_localtime(&t, &time_now, NULL);
07527 tv_now = ast_tvnow();
07528 ast_localtime(&tv_now, &time_then, NULL);
07529
07530
07531 if (time_now.tm_year == time_then.tm_year)
07532 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07533 else
07534 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07535 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07536
07537
07538 #endif
07539 if (the_zone) {
07540 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07541 } else if (!strncasecmp(chan->language, "de", 2)) {
07542 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07543 } else if (!strncasecmp(chan->language, "gr", 2)) {
07544 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07545 } else if (!strncasecmp(chan->language, "it", 2)) {
07546 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);
07547 } else if (!strncasecmp(chan->language, "nl", 2)) {
07548 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07549 } else if (!strncasecmp(chan->language, "no", 2)) {
07550 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07551 } else if (!strncasecmp(chan->language, "pl", 2)) {
07552 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07553 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07554 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);
07555 } else if (!strncasecmp(chan->language, "se", 2)) {
07556 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07557 } else if (!strncasecmp(chan->language, "zh", 2)) {
07558 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07559 } else if (!strncasecmp(chan->language, "vi", 2)) {
07560 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);
07561 } else {
07562 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07563 }
07564 #if 0
07565 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07566 #endif
07567 return res;
07568 }
07569
07570
07571
07572 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07573 {
07574 int res = 0;
07575 int i;
07576 char *callerid, *name;
07577 char prefile[PATH_MAX] = "";
07578
07579
07580
07581
07582
07583
07584
07585
07586
07587 if ((cid == NULL)||(context == NULL))
07588 return res;
07589
07590
07591 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07592 ast_callerid_parse(cid, &name, &callerid);
07593 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07594
07595
07596 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07597 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07598 if ((strcmp(cidinternalcontexts[i], context) == 0))
07599 break;
07600 }
07601 if (i != MAX_NUM_CID_CONTEXTS){
07602 if (!res) {
07603 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07604 if (!ast_strlen_zero(prefile)) {
07605
07606 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07607 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07608 if (!callback)
07609 res = wait_file2(chan, vms, "vm-from");
07610 res = ast_stream_and_wait(chan, prefile, "");
07611 } else {
07612 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07613
07614 if (!callback)
07615 res = wait_file2(chan, vms, "vm-from-extension");
07616 res = ast_say_digit_str(chan, callerid, "", chan->language);
07617 }
07618 }
07619 }
07620 } else if (!res) {
07621 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07622
07623 if (!callback)
07624 res = wait_file2(chan, vms, "vm-from-phonenumber");
07625 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07626 }
07627 } else {
07628
07629 ast_debug(1, "VM-CID: From an unknown number\n");
07630
07631 res = wait_file2(chan, vms, "vm-unknown-caller");
07632 }
07633 return res;
07634 }
07635
07636 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07637 {
07638 int res = 0;
07639 int durationm;
07640 int durations;
07641
07642 if (duration == NULL)
07643 return res;
07644
07645
07646 durations = atoi(duration);
07647 durationm = (durations / 60);
07648
07649 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07650
07651 if ((!res) && (durationm >= minduration)) {
07652 res = wait_file2(chan, vms, "vm-duration");
07653
07654
07655 if (!strncasecmp(chan->language, "pl", 2)) {
07656 div_t num = div(durationm, 10);
07657
07658 if (durationm == 1) {
07659 res = ast_play_and_wait(chan, "digits/1z");
07660 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07661 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07662 if (num.rem == 2) {
07663 if (!num.quot) {
07664 res = ast_play_and_wait(chan, "digits/2-ie");
07665 } else {
07666 res = say_and_wait(chan, durationm - 2 , chan->language);
07667 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07668 }
07669 } else {
07670 res = say_and_wait(chan, durationm, chan->language);
07671 }
07672 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07673 } else {
07674 res = say_and_wait(chan, durationm, chan->language);
07675 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07676 }
07677
07678 } else {
07679 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07680 res = wait_file2(chan, vms, "vm-minutes");
07681 }
07682 }
07683 return res;
07684 }
07685
07686 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07687 {
07688 int res = 0;
07689 char filename[256], *cid;
07690 const char *origtime, *context, *category, *duration, *flag;
07691 struct ast_config *msg_cfg;
07692 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07693
07694 vms->starting = 0;
07695 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07696 adsi_message(chan, vms);
07697 if (!vms->curmsg) {
07698 res = wait_file2(chan, vms, "vm-first");
07699 } else if (vms->curmsg == vms->lastmsg) {
07700 res = wait_file2(chan, vms, "vm-last");
07701 }
07702
07703 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07704 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07705 msg_cfg = ast_config_load(filename, config_flags);
07706 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07707 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07708 return 0;
07709 }
07710 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07711
07712
07713 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07714 res = wait_file2(chan, vms, "vm-Urgent");
07715 }
07716
07717 if (!res) {
07718
07719
07720 if (!strncasecmp(chan->language, "pl", 2)) {
07721 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07722 int ten, one;
07723 char nextmsg[256];
07724 ten = (vms->curmsg + 1) / 10;
07725 one = (vms->curmsg + 1) % 10;
07726
07727 if (vms->curmsg < 20) {
07728 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07729 res = wait_file2(chan, vms, nextmsg);
07730 } else {
07731 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07732 res = wait_file2(chan, vms, nextmsg);
07733 if (one > 0) {
07734 if (!res) {
07735 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07736 res = wait_file2(chan, vms, nextmsg);
07737 }
07738 }
07739 }
07740 }
07741 if (!res)
07742 res = wait_file2(chan, vms, "vm-message");
07743
07744 } else if (!strncasecmp(chan->language, "he", 2)) {
07745 if (!vms->curmsg) {
07746 res = wait_file2(chan, vms, "vm-message");
07747 res = wait_file2(chan, vms, "vm-first");
07748 } else if (vms->curmsg == vms->lastmsg) {
07749 res = wait_file2(chan, vms, "vm-message");
07750 res = wait_file2(chan, vms, "vm-last");
07751 } else {
07752 res = wait_file2(chan, vms, "vm-message");
07753 res = wait_file2(chan, vms, "vm-number");
07754 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07755 }
07756
07757 } else if (!strncasecmp(chan->language, "vi", 2)) {
07758 if (!vms->curmsg) {
07759 res = wait_file2(chan, vms, "vm-message");
07760 res = wait_file2(chan, vms, "vm-first");
07761 } else if (vms->curmsg == vms->lastmsg) {
07762 res = wait_file2(chan, vms, "vm-message");
07763 res = wait_file2(chan, vms, "vm-last");
07764 } else {
07765 res = wait_file2(chan, vms, "vm-message");
07766 res = wait_file2(chan, vms, "vm-number");
07767 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07768 }
07769 } else {
07770 if (!strncasecmp(chan->language, "se", 2)) {
07771 res = wait_file2(chan, vms, "vm-meddelandet");
07772 } else {
07773 res = wait_file2(chan, vms, "vm-message");
07774 }
07775 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07776 if (!res) {
07777 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07778 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07779 }
07780 }
07781 }
07782 }
07783
07784 if (!msg_cfg) {
07785 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07786 return 0;
07787 }
07788
07789 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07790 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07791 DISPOSE(vms->curdir, vms->curmsg);
07792 ast_config_destroy(msg_cfg);
07793 return 0;
07794 }
07795
07796 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07797 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07798 category = ast_variable_retrieve(msg_cfg, "message", "category");
07799
07800 context = ast_variable_retrieve(msg_cfg, "message", "context");
07801 if (!strncasecmp("macro", context, 5))
07802 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07803 if (!res) {
07804 res = play_message_category(chan, category);
07805 }
07806 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07807 res = play_message_datetime(chan, vmu, origtime, filename);
07808 }
07809 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07810 res = play_message_callerid(chan, vms, cid, context, 0);
07811 }
07812 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07813 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07814 }
07815
07816 if (res == '1') {
07817 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07818 res = 0;
07819 }
07820 ast_config_destroy(msg_cfg);
07821
07822 if (!res) {
07823 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07824 #ifdef IMAP_STORAGE
07825 ast_mutex_lock(&vms->lock);
07826 #endif
07827 vms->heard[vms->curmsg] = 1;
07828 #ifdef IMAP_STORAGE
07829 ast_mutex_unlock(&vms->lock);
07830
07831
07832
07833 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07834 wait_file(chan, vms, vms->introfn);
07835 }
07836 #endif
07837 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07838 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07839 res = 0;
07840 }
07841 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07842 }
07843 DISPOSE(vms->curdir, vms->curmsg);
07844 return res;
07845 }
07846
07847 #ifdef IMAP_STORAGE
07848 static int imap_remove_file(char *dir, int msgnum)
07849 {
07850 char fn[PATH_MAX];
07851 char full_fn[PATH_MAX];
07852 char intro[PATH_MAX] = {0,};
07853
07854 if (msgnum > -1) {
07855 make_file(fn, sizeof(fn), dir, msgnum);
07856 snprintf(intro, sizeof(intro), "%sintro", fn);
07857 } else
07858 ast_copy_string(fn, dir, sizeof(fn));
07859
07860 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07861 ast_filedelete(fn, NULL);
07862 if (!ast_strlen_zero(intro)) {
07863 ast_filedelete(intro, NULL);
07864 }
07865 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07866 unlink(full_fn);
07867 }
07868 return 0;
07869 }
07870
07871
07872
07873 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07874 {
07875 char *file, *filename;
07876 char *attachment;
07877 char arg[10];
07878 int i;
07879 BODY* body;
07880
07881 file = strrchr(ast_strdupa(dir), '/');
07882 if (file) {
07883 *file++ = '\0';
07884 } else {
07885 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07886 return -1;
07887 }
07888
07889 ast_mutex_lock(&vms->lock);
07890 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07891 mail_fetchstructure(vms->mailstream, i + 1, &body);
07892
07893 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07894 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07895 } else {
07896 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07897 ast_mutex_unlock(&vms->lock);
07898 return -1;
07899 }
07900 filename = strsep(&attachment, ".");
07901 if (!strcmp(filename, file)) {
07902 sprintf(arg, "%d", i + 1);
07903 mail_setflag(vms->mailstream, arg, "\\DELETED");
07904 }
07905 }
07906 mail_expunge(vms->mailstream);
07907 ast_mutex_unlock(&vms->lock);
07908 return 0;
07909 }
07910
07911 #elif !defined(IMAP_STORAGE)
07912 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07913 {
07914 int count_msg, last_msg;
07915
07916 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07917
07918
07919
07920
07921 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07922
07923
07924 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07925
07926
07927 count_msg = count_messages(vmu, vms->curdir);
07928 if (count_msg < 0) {
07929 return count_msg;
07930 } else {
07931 vms->lastmsg = count_msg - 1;
07932 }
07933
07934 if (vm_allocate_dh(vms, vmu, count_msg)) {
07935 return -1;
07936 }
07937
07938
07939
07940
07941
07942
07943
07944
07945 if (vm_lock_path(vms->curdir)) {
07946 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07947 return ERROR_LOCK_PATH;
07948 }
07949
07950
07951 last_msg = last_message_index(vmu, vms->curdir);
07952 ast_unlock_path(vms->curdir);
07953
07954 if (last_msg < -1) {
07955 return last_msg;
07956 } else if (vms->lastmsg != last_msg) {
07957 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);
07958 resequence_mailbox(vmu, vms->curdir, count_msg);
07959 }
07960
07961 return 0;
07962 }
07963 #endif
07964
07965 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07966 {
07967 int x = 0;
07968 int last_msg_idx = 0;
07969
07970 #ifndef IMAP_STORAGE
07971 int res = 0, nummsg;
07972 char fn2[PATH_MAX];
07973 #endif
07974
07975 if (vms->lastmsg <= -1) {
07976 goto done;
07977 }
07978
07979 vms->curmsg = -1;
07980 #ifndef IMAP_STORAGE
07981
07982 if (vm_lock_path(vms->curdir)) {
07983 return ERROR_LOCK_PATH;
07984 }
07985
07986
07987 last_msg_idx = last_message_index(vmu, vms->curdir);
07988 if (last_msg_idx != vms->lastmsg) {
07989 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
07990 }
07991
07992
07993 for (x = 0; x < last_msg_idx + 1; x++) {
07994 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07995
07996 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07997 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07998 break;
07999 }
08000 vms->curmsg++;
08001 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08002 if (strcmp(vms->fn, fn2)) {
08003 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08004 }
08005 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08006
08007 res = save_to_folder(vmu, vms, x, 1);
08008 if (res == ERROR_LOCK_PATH) {
08009
08010 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08011 vms->deleted[x] = 0;
08012 vms->heard[x] = 0;
08013 --x;
08014 }
08015 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08016
08017 res = save_to_folder(vmu, vms, x, 10);
08018 if (res == ERROR_LOCK_PATH) {
08019
08020 vms->deleted[x] = 0;
08021 vms->heard[x] = 0;
08022 --x;
08023 }
08024 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08025
08026
08027 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08028 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08029 DELETE(vms->curdir, x, vms->fn, vmu);
08030 }
08031 }
08032 }
08033
08034
08035 nummsg = x - 1;
08036 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08037 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08038 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08039 DELETE(vms->curdir, x, vms->fn, vmu);
08040 }
08041 }
08042 ast_unlock_path(vms->curdir);
08043 #else
08044 ast_mutex_lock(&vms->lock);
08045 if (vms->deleted) {
08046
08047
08048 last_msg_idx = vms->dh_arraysize;
08049 for (x = last_msg_idx - 1; x >= 0; x--) {
08050 if (vms->deleted[x]) {
08051 ast_debug(3, "IMAP delete of %d\n", x);
08052 DELETE(vms->curdir, x, vms->fn, vmu);
08053 }
08054 }
08055 }
08056 #endif
08057
08058 done:
08059 if (vms->deleted) {
08060 ast_free(vms->deleted);
08061 vms->deleted = NULL;
08062 }
08063 if (vms->heard) {
08064 ast_free(vms->heard);
08065 vms->heard = NULL;
08066 }
08067 vms->dh_arraysize = 0;
08068 #ifdef IMAP_STORAGE
08069 ast_mutex_unlock(&vms->lock);
08070 #endif
08071
08072 return 0;
08073 }
08074
08075
08076
08077
08078
08079
08080
08081 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08082 {
08083 int cmd;
08084 char *buf;
08085
08086 buf = alloca(strlen(box) + 2);
08087 strcpy(buf, box);
08088 strcat(buf, "s");
08089
08090 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08091 cmd = ast_play_and_wait(chan, buf);
08092 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08093 } else {
08094 cmd = ast_play_and_wait(chan, "vm-messages");
08095 return cmd ? cmd : ast_play_and_wait(chan, box);
08096 }
08097 }
08098
08099 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08100 {
08101 int cmd;
08102
08103 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08104 if (!strcasecmp(box, "vm-INBOX"))
08105 cmd = ast_play_and_wait(chan, "vm-new-e");
08106 else
08107 cmd = ast_play_and_wait(chan, "vm-old-e");
08108 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08109 } else {
08110 cmd = ast_play_and_wait(chan, "vm-messages");
08111 return cmd ? cmd : ast_play_and_wait(chan, box);
08112 }
08113 }
08114
08115 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08116 {
08117 int cmd;
08118
08119 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08120 cmd = ast_play_and_wait(chan, "vm-messages");
08121 return cmd ? cmd : ast_play_and_wait(chan, box);
08122 } else {
08123 cmd = ast_play_and_wait(chan, box);
08124 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08125 }
08126 }
08127
08128 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08129 {
08130 int cmd;
08131
08132 if ( !strncasecmp(chan->language, "it", 2) ||
08133 !strncasecmp(chan->language, "es", 2) ||
08134 !strncasecmp(chan->language, "pt", 2)) {
08135 cmd = ast_play_and_wait(chan, "vm-messages");
08136 return cmd ? cmd : ast_play_and_wait(chan, box);
08137 } else if (!strncasecmp(chan->language, "gr", 2)) {
08138 return vm_play_folder_name_gr(chan, box);
08139 } else if (!strncasecmp(chan->language, "he", 2)) {
08140 return ast_play_and_wait(chan, box);
08141 } else if (!strncasecmp(chan->language, "pl", 2)) {
08142 return vm_play_folder_name_pl(chan, box);
08143 } else if (!strncasecmp(chan->language, "ua", 2)) {
08144 return vm_play_folder_name_ua(chan, box);
08145 } else if (!strncasecmp(chan->language, "vi", 2)) {
08146 return ast_play_and_wait(chan, box);
08147 } else {
08148 cmd = ast_play_and_wait(chan, box);
08149 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08150 }
08151 }
08152
08153
08154
08155
08156
08157
08158
08159
08160
08161
08162
08163
08164
08165 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08166 {
08167 int res = 0;
08168
08169 if (vms->newmessages) {
08170 res = ast_play_and_wait(chan, "vm-youhave");
08171 if (!res)
08172 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08173 if (!res) {
08174 if ((vms->newmessages == 1)) {
08175 res = ast_play_and_wait(chan, "vm-INBOX");
08176 if (!res)
08177 res = ast_play_and_wait(chan, "vm-message");
08178 } else {
08179 res = ast_play_and_wait(chan, "vm-INBOXs");
08180 if (!res)
08181 res = ast_play_and_wait(chan, "vm-messages");
08182 }
08183 }
08184 } else if (vms->oldmessages){
08185 res = ast_play_and_wait(chan, "vm-youhave");
08186 if (!res)
08187 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08188 if ((vms->oldmessages == 1)){
08189 res = ast_play_and_wait(chan, "vm-Old");
08190 if (!res)
08191 res = ast_play_and_wait(chan, "vm-message");
08192 } else {
08193 res = ast_play_and_wait(chan, "vm-Olds");
08194 if (!res)
08195 res = ast_play_and_wait(chan, "vm-messages");
08196 }
08197 } else if (!vms->oldmessages && !vms->newmessages)
08198 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08199 return res;
08200 }
08201
08202
08203
08204
08205
08206
08207
08208
08209
08210
08211
08212
08213
08214
08215
08216
08217
08218
08219
08220
08221
08222
08223
08224
08225
08226
08227
08228
08229
08230
08231
08232
08233
08234
08235
08236
08237
08238
08239
08240
08241
08242
08243
08244
08245
08246
08247
08248
08249
08250
08251
08252
08253
08254
08255
08256
08257
08258
08259 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08260 {
08261 int res;
08262 int lastnum = 0;
08263
08264 res = ast_play_and_wait(chan, "vm-youhave");
08265
08266 if (!res && vms->newmessages) {
08267 lastnum = vms->newmessages;
08268
08269 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08270 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08271 }
08272
08273 if (!res && vms->oldmessages) {
08274 res = ast_play_and_wait(chan, "vm-and");
08275 }
08276 }
08277
08278 if (!res && vms->oldmessages) {
08279 lastnum = vms->oldmessages;
08280
08281 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08282 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08283 }
08284 }
08285
08286 if (!res) {
08287 if (lastnum == 0) {
08288 res = ast_play_and_wait(chan, "vm-no");
08289 }
08290 if (!res) {
08291 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08292 }
08293 }
08294
08295 return res;
08296 }
08297
08298
08299 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08300 {
08301 int res = 0;
08302
08303
08304 if (!res) {
08305 if ((vms->newmessages) || (vms->oldmessages)) {
08306 res = ast_play_and_wait(chan, "vm-youhave");
08307 }
08308
08309
08310
08311
08312
08313 if (vms->newmessages) {
08314 if (!res) {
08315 if (vms->newmessages == 1) {
08316 res = ast_play_and_wait(chan, "vm-INBOX1");
08317 } else {
08318 if (vms->newmessages == 2) {
08319 res = ast_play_and_wait(chan, "vm-shtei");
08320 } else {
08321 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08322 }
08323 res = ast_play_and_wait(chan, "vm-INBOX");
08324 }
08325 }
08326 if (vms->oldmessages && !res) {
08327 res = ast_play_and_wait(chan, "vm-and");
08328 if (vms->oldmessages == 1) {
08329 res = ast_play_and_wait(chan, "vm-Old1");
08330 } else {
08331 if (vms->oldmessages == 2) {
08332 res = ast_play_and_wait(chan, "vm-shtei");
08333 } else {
08334 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08335 }
08336 res = ast_play_and_wait(chan, "vm-Old");
08337 }
08338 }
08339 }
08340 if (!res && vms->oldmessages && !vms->newmessages) {
08341 if (!res) {
08342 if (vms->oldmessages == 1) {
08343 res = ast_play_and_wait(chan, "vm-Old1");
08344 } else {
08345 if (vms->oldmessages == 2) {
08346 res = ast_play_and_wait(chan, "vm-shtei");
08347 } else {
08348 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08349 }
08350 res = ast_play_and_wait(chan, "vm-Old");
08351 }
08352 }
08353 }
08354 if (!res) {
08355 if (!vms->oldmessages && !vms->newmessages) {
08356 if (!res) {
08357 res = ast_play_and_wait(chan, "vm-nomessages");
08358 }
08359 }
08360 }
08361 }
08362 return res;
08363 }
08364
08365
08366 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08367 {
08368 int res;
08369
08370
08371 res = ast_play_and_wait(chan, "vm-youhave");
08372 if (!res) {
08373 if (vms->urgentmessages) {
08374 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08375 if (!res)
08376 res = ast_play_and_wait(chan, "vm-Urgent");
08377 if ((vms->oldmessages || vms->newmessages) && !res) {
08378 res = ast_play_and_wait(chan, "vm-and");
08379 } else if (!res) {
08380 if ((vms->urgentmessages == 1))
08381 res = ast_play_and_wait(chan, "vm-message");
08382 else
08383 res = ast_play_and_wait(chan, "vm-messages");
08384 }
08385 }
08386 if (vms->newmessages) {
08387 res = say_and_wait(chan, vms->newmessages, chan->language);
08388 if (!res)
08389 res = ast_play_and_wait(chan, "vm-INBOX");
08390 if (vms->oldmessages && !res)
08391 res = ast_play_and_wait(chan, "vm-and");
08392 else if (!res) {
08393 if ((vms->newmessages == 1))
08394 res = ast_play_and_wait(chan, "vm-message");
08395 else
08396 res = ast_play_and_wait(chan, "vm-messages");
08397 }
08398
08399 }
08400 if (!res && vms->oldmessages) {
08401 res = say_and_wait(chan, vms->oldmessages, chan->language);
08402 if (!res)
08403 res = ast_play_and_wait(chan, "vm-Old");
08404 if (!res) {
08405 if (vms->oldmessages == 1)
08406 res = ast_play_and_wait(chan, "vm-message");
08407 else
08408 res = ast_play_and_wait(chan, "vm-messages");
08409 }
08410 }
08411 if (!res) {
08412 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08413 res = ast_play_and_wait(chan, "vm-no");
08414 if (!res)
08415 res = ast_play_and_wait(chan, "vm-messages");
08416 }
08417 }
08418 }
08419 return res;
08420 }
08421
08422
08423 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08424 {
08425
08426 int res;
08427 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08428 res = ast_play_and_wait(chan, "vm-no") ||
08429 ast_play_and_wait(chan, "vm-message");
08430 else
08431 res = ast_play_and_wait(chan, "vm-youhave");
08432 if (!res && vms->newmessages) {
08433 res = (vms->newmessages == 1) ?
08434 ast_play_and_wait(chan, "digits/un") ||
08435 ast_play_and_wait(chan, "vm-nuovo") ||
08436 ast_play_and_wait(chan, "vm-message") :
08437
08438 say_and_wait(chan, vms->newmessages, chan->language) ||
08439 ast_play_and_wait(chan, "vm-nuovi") ||
08440 ast_play_and_wait(chan, "vm-messages");
08441 if (!res && vms->oldmessages)
08442 res = ast_play_and_wait(chan, "vm-and");
08443 }
08444 if (!res && vms->oldmessages) {
08445 res = (vms->oldmessages == 1) ?
08446 ast_play_and_wait(chan, "digits/un") ||
08447 ast_play_and_wait(chan, "vm-vecchio") ||
08448 ast_play_and_wait(chan, "vm-message") :
08449
08450 say_and_wait(chan, vms->oldmessages, chan->language) ||
08451 ast_play_and_wait(chan, "vm-vecchi") ||
08452 ast_play_and_wait(chan, "vm-messages");
08453 }
08454 return res;
08455 }
08456
08457
08458 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08459 {
08460
08461 int res;
08462 div_t num;
08463
08464 if (!vms->oldmessages && !vms->newmessages) {
08465 res = ast_play_and_wait(chan, "vm-no");
08466 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08467 return res;
08468 } else {
08469 res = ast_play_and_wait(chan, "vm-youhave");
08470 }
08471
08472 if (vms->newmessages) {
08473 num = div(vms->newmessages, 10);
08474 if (vms->newmessages == 1) {
08475 res = ast_play_and_wait(chan, "digits/1-a");
08476 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08477 res = res ? res : ast_play_and_wait(chan, "vm-message");
08478 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08479 if (num.rem == 2) {
08480 if (!num.quot) {
08481 res = ast_play_and_wait(chan, "digits/2-ie");
08482 } else {
08483 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08484 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08485 }
08486 } else {
08487 res = say_and_wait(chan, vms->newmessages, chan->language);
08488 }
08489 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08490 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08491 } else {
08492 res = say_and_wait(chan, vms->newmessages, chan->language);
08493 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08494 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08495 }
08496 if (!res && vms->oldmessages)
08497 res = ast_play_and_wait(chan, "vm-and");
08498 }
08499 if (!res && vms->oldmessages) {
08500 num = div(vms->oldmessages, 10);
08501 if (vms->oldmessages == 1) {
08502 res = ast_play_and_wait(chan, "digits/1-a");
08503 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08504 res = res ? res : ast_play_and_wait(chan, "vm-message");
08505 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08506 if (num.rem == 2) {
08507 if (!num.quot) {
08508 res = ast_play_and_wait(chan, "digits/2-ie");
08509 } else {
08510 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08511 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08512 }
08513 } else {
08514 res = say_and_wait(chan, vms->oldmessages, chan->language);
08515 }
08516 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08517 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08518 } else {
08519 res = say_and_wait(chan, vms->oldmessages, chan->language);
08520 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08521 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08522 }
08523 }
08524
08525 return res;
08526 }
08527
08528
08529 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08530 {
08531
08532 int res;
08533
08534 res = ast_play_and_wait(chan, "vm-youhave");
08535 if (res)
08536 return res;
08537
08538 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08539 res = ast_play_and_wait(chan, "vm-no");
08540 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08541 return res;
08542 }
08543
08544 if (vms->newmessages) {
08545 if ((vms->newmessages == 1)) {
08546 res = ast_play_and_wait(chan, "digits/ett");
08547 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08548 res = res ? res : ast_play_and_wait(chan, "vm-message");
08549 } else {
08550 res = say_and_wait(chan, vms->newmessages, chan->language);
08551 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08552 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08553 }
08554 if (!res && vms->oldmessages)
08555 res = ast_play_and_wait(chan, "vm-and");
08556 }
08557 if (!res && vms->oldmessages) {
08558 if (vms->oldmessages == 1) {
08559 res = ast_play_and_wait(chan, "digits/ett");
08560 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08561 res = res ? res : ast_play_and_wait(chan, "vm-message");
08562 } else {
08563 res = say_and_wait(chan, vms->oldmessages, chan->language);
08564 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08565 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08566 }
08567 }
08568
08569 return res;
08570 }
08571
08572
08573 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08574 {
08575
08576 int res;
08577
08578 res = ast_play_and_wait(chan, "vm-youhave");
08579 if (res)
08580 return res;
08581
08582 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08583 res = ast_play_and_wait(chan, "vm-no");
08584 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08585 return res;
08586 }
08587
08588 if (vms->newmessages) {
08589 if ((vms->newmessages == 1)) {
08590 res = ast_play_and_wait(chan, "digits/1");
08591 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08592 res = res ? res : ast_play_and_wait(chan, "vm-message");
08593 } else {
08594 res = say_and_wait(chan, vms->newmessages, chan->language);
08595 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08596 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08597 }
08598 if (!res && vms->oldmessages)
08599 res = ast_play_and_wait(chan, "vm-and");
08600 }
08601 if (!res && vms->oldmessages) {
08602 if (vms->oldmessages == 1) {
08603 res = ast_play_and_wait(chan, "digits/1");
08604 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08605 res = res ? res : ast_play_and_wait(chan, "vm-message");
08606 } else {
08607 res = say_and_wait(chan, vms->oldmessages, chan->language);
08608 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08609 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08610 }
08611 }
08612
08613 return res;
08614 }
08615
08616
08617 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08618 {
08619
08620 int res;
08621 res = ast_play_and_wait(chan, "vm-youhave");
08622 if (!res) {
08623 if (vms->newmessages) {
08624 if ((vms->newmessages == 1))
08625 res = ast_play_and_wait(chan, "digits/1F");
08626 else
08627 res = say_and_wait(chan, vms->newmessages, chan->language);
08628 if (!res)
08629 res = ast_play_and_wait(chan, "vm-INBOX");
08630 if (vms->oldmessages && !res)
08631 res = ast_play_and_wait(chan, "vm-and");
08632 else if (!res) {
08633 if ((vms->newmessages == 1))
08634 res = ast_play_and_wait(chan, "vm-message");
08635 else
08636 res = ast_play_and_wait(chan, "vm-messages");
08637 }
08638
08639 }
08640 if (!res && vms->oldmessages) {
08641 if (vms->oldmessages == 1)
08642 res = ast_play_and_wait(chan, "digits/1F");
08643 else
08644 res = say_and_wait(chan, vms->oldmessages, chan->language);
08645 if (!res)
08646 res = ast_play_and_wait(chan, "vm-Old");
08647 if (!res) {
08648 if (vms->oldmessages == 1)
08649 res = ast_play_and_wait(chan, "vm-message");
08650 else
08651 res = ast_play_and_wait(chan, "vm-messages");
08652 }
08653 }
08654 if (!res) {
08655 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08656 res = ast_play_and_wait(chan, "vm-no");
08657 if (!res)
08658 res = ast_play_and_wait(chan, "vm-messages");
08659 }
08660 }
08661 }
08662 return res;
08663 }
08664
08665
08666 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08667 {
08668
08669 int res;
08670 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08671 res = ast_play_and_wait(chan, "vm-youhaveno");
08672 if (!res)
08673 res = ast_play_and_wait(chan, "vm-messages");
08674 } else {
08675 res = ast_play_and_wait(chan, "vm-youhave");
08676 }
08677 if (!res) {
08678 if (vms->newmessages) {
08679 if (!res) {
08680 if ((vms->newmessages == 1)) {
08681 res = ast_play_and_wait(chan, "digits/1M");
08682 if (!res)
08683 res = ast_play_and_wait(chan, "vm-message");
08684 if (!res)
08685 res = ast_play_and_wait(chan, "vm-INBOXs");
08686 } else {
08687 res = say_and_wait(chan, vms->newmessages, chan->language);
08688 if (!res)
08689 res = ast_play_and_wait(chan, "vm-messages");
08690 if (!res)
08691 res = ast_play_and_wait(chan, "vm-INBOX");
08692 }
08693 }
08694 if (vms->oldmessages && !res)
08695 res = ast_play_and_wait(chan, "vm-and");
08696 }
08697 if (vms->oldmessages) {
08698 if (!res) {
08699 if (vms->oldmessages == 1) {
08700 res = ast_play_and_wait(chan, "digits/1M");
08701 if (!res)
08702 res = ast_play_and_wait(chan, "vm-message");
08703 if (!res)
08704 res = ast_play_and_wait(chan, "vm-Olds");
08705 } else {
08706 res = say_and_wait(chan, vms->oldmessages, chan->language);
08707 if (!res)
08708 res = ast_play_and_wait(chan, "vm-messages");
08709 if (!res)
08710 res = ast_play_and_wait(chan, "vm-Old");
08711 }
08712 }
08713 }
08714 }
08715 return res;
08716 }
08717
08718
08719 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08720
08721 int res;
08722 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08723 res = ast_play_and_wait(chan, "vm-nomessages");
08724 return res;
08725 } else {
08726 res = ast_play_and_wait(chan, "vm-youhave");
08727 }
08728 if (vms->newmessages) {
08729 if (!res)
08730 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08731 if ((vms->newmessages == 1)) {
08732 if (!res)
08733 res = ast_play_and_wait(chan, "vm-message");
08734 if (!res)
08735 res = ast_play_and_wait(chan, "vm-INBOXs");
08736 } else {
08737 if (!res)
08738 res = ast_play_and_wait(chan, "vm-messages");
08739 if (!res)
08740 res = ast_play_and_wait(chan, "vm-INBOX");
08741 }
08742 if (vms->oldmessages && !res)
08743 res = ast_play_and_wait(chan, "vm-and");
08744 }
08745 if (vms->oldmessages) {
08746 if (!res)
08747 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08748 if (vms->oldmessages == 1) {
08749 if (!res)
08750 res = ast_play_and_wait(chan, "vm-message");
08751 if (!res)
08752 res = ast_play_and_wait(chan, "vm-Olds");
08753 } else {
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 return res;
08761 }
08762
08763
08764 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08765 {
08766
08767 int res;
08768 res = ast_play_and_wait(chan, "vm-youhave");
08769 if (!res) {
08770 if (vms->newmessages) {
08771 res = say_and_wait(chan, vms->newmessages, chan->language);
08772 if (!res)
08773 res = ast_play_and_wait(chan, "vm-INBOX");
08774 if (vms->oldmessages && !res)
08775 res = ast_play_and_wait(chan, "vm-and");
08776 else if (!res) {
08777 if ((vms->newmessages == 1))
08778 res = ast_play_and_wait(chan, "vm-message");
08779 else
08780 res = ast_play_and_wait(chan, "vm-messages");
08781 }
08782
08783 }
08784 if (!res && vms->oldmessages) {
08785 res = say_and_wait(chan, vms->oldmessages, chan->language);
08786 if (!res)
08787 res = ast_play_and_wait(chan, "vm-Old");
08788 if (!res) {
08789 if (vms->oldmessages == 1)
08790 res = ast_play_and_wait(chan, "vm-message");
08791 else
08792 res = ast_play_and_wait(chan, "vm-messages");
08793 }
08794 }
08795 if (!res) {
08796 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08797 res = ast_play_and_wait(chan, "vm-no");
08798 if (!res)
08799 res = ast_play_and_wait(chan, "vm-messages");
08800 }
08801 }
08802 }
08803 return res;
08804 }
08805
08806
08807 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08808 {
08809
08810 int res;
08811 res = ast_play_and_wait(chan, "vm-youhave");
08812 if (!res) {
08813 if (vms->newmessages) {
08814 res = say_and_wait(chan, vms->newmessages, chan->language);
08815 if (!res) {
08816 if (vms->newmessages == 1)
08817 res = ast_play_and_wait(chan, "vm-INBOXs");
08818 else
08819 res = ast_play_and_wait(chan, "vm-INBOX");
08820 }
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 if (vms->oldmessages == 1)
08835 res = ast_play_and_wait(chan, "vm-Olds");
08836 else
08837 res = ast_play_and_wait(chan, "vm-Old");
08838 }
08839 if (!res) {
08840 if (vms->oldmessages == 1)
08841 res = ast_play_and_wait(chan, "vm-message");
08842 else
08843 res = ast_play_and_wait(chan, "vm-messages");
08844 }
08845 }
08846 if (!res) {
08847 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08848 res = ast_play_and_wait(chan, "vm-no");
08849 if (!res)
08850 res = ast_play_and_wait(chan, "vm-messages");
08851 }
08852 }
08853 }
08854 return res;
08855 }
08856
08857
08858 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08859 {
08860
08861 int res;
08862 res = ast_play_and_wait(chan, "vm-youhave");
08863 if (!res) {
08864 if (vms->newmessages) {
08865 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08866 if (!res) {
08867 if ((vms->newmessages == 1)) {
08868 res = ast_play_and_wait(chan, "vm-message");
08869 if (!res)
08870 res = ast_play_and_wait(chan, "vm-INBOXs");
08871 } else {
08872 res = ast_play_and_wait(chan, "vm-messages");
08873 if (!res)
08874 res = ast_play_and_wait(chan, "vm-INBOX");
08875 }
08876 }
08877 if (vms->oldmessages && !res)
08878 res = ast_play_and_wait(chan, "vm-and");
08879 }
08880 if (!res && vms->oldmessages) {
08881 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08882 if (!res) {
08883 if (vms->oldmessages == 1) {
08884 res = ast_play_and_wait(chan, "vm-message");
08885 if (!res)
08886 res = ast_play_and_wait(chan, "vm-Olds");
08887 } else {
08888 res = ast_play_and_wait(chan, "vm-messages");
08889 if (!res)
08890 res = ast_play_and_wait(chan, "vm-Old");
08891 }
08892 }
08893 }
08894 if (!res) {
08895 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08896 res = ast_play_and_wait(chan, "vm-no");
08897 if (!res)
08898 res = ast_play_and_wait(chan, "vm-messages");
08899 }
08900 }
08901 }
08902 return res;
08903 }
08904
08905
08906
08907
08908
08909
08910
08911
08912
08913
08914
08915
08916
08917
08918
08919
08920
08921 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08922 {
08923 int res;
08924 res = ast_play_and_wait(chan, "vm-youhave");
08925 if (!res) {
08926 if (vms->newmessages) {
08927 if (vms->newmessages == 1) {
08928 res = ast_play_and_wait(chan, "digits/jednu");
08929 } else {
08930 res = say_and_wait(chan, vms->newmessages, chan->language);
08931 }
08932 if (!res) {
08933 if ((vms->newmessages == 1))
08934 res = ast_play_and_wait(chan, "vm-novou");
08935 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08936 res = ast_play_and_wait(chan, "vm-nove");
08937 if (vms->newmessages > 4)
08938 res = ast_play_and_wait(chan, "vm-novych");
08939 }
08940 if (vms->oldmessages && !res)
08941 res = ast_play_and_wait(chan, "vm-and");
08942 else if (!res) {
08943 if ((vms->newmessages == 1))
08944 res = ast_play_and_wait(chan, "vm-zpravu");
08945 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08946 res = ast_play_and_wait(chan, "vm-zpravy");
08947 if (vms->newmessages > 4)
08948 res = ast_play_and_wait(chan, "vm-zprav");
08949 }
08950 }
08951 if (!res && vms->oldmessages) {
08952 res = say_and_wait(chan, vms->oldmessages, chan->language);
08953 if (!res) {
08954 if ((vms->oldmessages == 1))
08955 res = ast_play_and_wait(chan, "vm-starou");
08956 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08957 res = ast_play_and_wait(chan, "vm-stare");
08958 if (vms->oldmessages > 4)
08959 res = ast_play_and_wait(chan, "vm-starych");
08960 }
08961 if (!res) {
08962 if ((vms->oldmessages == 1))
08963 res = ast_play_and_wait(chan, "vm-zpravu");
08964 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08965 res = ast_play_and_wait(chan, "vm-zpravy");
08966 if (vms->oldmessages > 4)
08967 res = ast_play_and_wait(chan, "vm-zprav");
08968 }
08969 }
08970 if (!res) {
08971 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08972 res = ast_play_and_wait(chan, "vm-no");
08973 if (!res)
08974 res = ast_play_and_wait(chan, "vm-zpravy");
08975 }
08976 }
08977 }
08978 return res;
08979 }
08980
08981
08982 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08983 {
08984 int res;
08985
08986 res = ast_play_and_wait(chan, "vm-you");
08987
08988 if (!res && vms->newmessages) {
08989 res = ast_play_and_wait(chan, "vm-have");
08990 if (!res)
08991 res = say_and_wait(chan, vms->newmessages, chan->language);
08992 if (!res)
08993 res = ast_play_and_wait(chan, "vm-tong");
08994 if (!res)
08995 res = ast_play_and_wait(chan, "vm-INBOX");
08996 if (vms->oldmessages && !res)
08997 res = ast_play_and_wait(chan, "vm-and");
08998 else if (!res)
08999 res = ast_play_and_wait(chan, "vm-messages");
09000 }
09001 if (!res && vms->oldmessages) {
09002 res = ast_play_and_wait(chan, "vm-have");
09003 if (!res)
09004 res = say_and_wait(chan, vms->oldmessages, chan->language);
09005 if (!res)
09006 res = ast_play_and_wait(chan, "vm-tong");
09007 if (!res)
09008 res = ast_play_and_wait(chan, "vm-Old");
09009 if (!res)
09010 res = ast_play_and_wait(chan, "vm-messages");
09011 }
09012 if (!res && !vms->oldmessages && !vms->newmessages) {
09013 res = ast_play_and_wait(chan, "vm-haveno");
09014 if (!res)
09015 res = ast_play_and_wait(chan, "vm-messages");
09016 }
09017 return res;
09018 }
09019
09020
09021 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09022 {
09023 int res;
09024
09025
09026 res = ast_play_and_wait(chan, "vm-youhave");
09027 if (!res) {
09028 if (vms->newmessages) {
09029 res = say_and_wait(chan, vms->newmessages, chan->language);
09030 if (!res)
09031 res = ast_play_and_wait(chan, "vm-INBOX");
09032 if (vms->oldmessages && !res)
09033 res = ast_play_and_wait(chan, "vm-and");
09034 }
09035 if (!res && vms->oldmessages) {
09036 res = say_and_wait(chan, vms->oldmessages, chan->language);
09037 if (!res)
09038 res = ast_play_and_wait(chan, "vm-Old");
09039 }
09040 if (!res) {
09041 if (!vms->oldmessages && !vms->newmessages) {
09042 res = ast_play_and_wait(chan, "vm-no");
09043 if (!res)
09044 res = ast_play_and_wait(chan, "vm-message");
09045 }
09046 }
09047 }
09048 return res;
09049 }
09050
09051 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09052 {
09053 char prefile[256];
09054
09055
09056 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09057 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09058 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09059 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09060 ast_play_and_wait(chan, "vm-tempgreetactive");
09061 }
09062 DISPOSE(prefile, -1);
09063 }
09064
09065
09066 if (0) {
09067 return 0;
09068 } else if (!strncasecmp(chan->language, "cs", 2)) {
09069 return vm_intro_cs(chan, vms);
09070 } else if (!strncasecmp(chan->language, "cz", 2)) {
09071 static int deprecation_warning = 0;
09072 if (deprecation_warning++ % 10 == 0) {
09073 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09074 }
09075 return vm_intro_cs(chan, vms);
09076 } else if (!strncasecmp(chan->language, "de", 2)) {
09077 return vm_intro_de(chan, vms);
09078 } else if (!strncasecmp(chan->language, "es", 2)) {
09079 return vm_intro_es(chan, vms);
09080 } else if (!strncasecmp(chan->language, "fr", 2)) {
09081 return vm_intro_fr(chan, vms);
09082 } else if (!strncasecmp(chan->language, "gr", 2)) {
09083 return vm_intro_gr(chan, vms);
09084 } else if (!strncasecmp(chan->language, "he", 2)) {
09085 return vm_intro_he(chan, vms);
09086 } else if (!strncasecmp(chan->language, "it", 2)) {
09087 return vm_intro_it(chan, vms);
09088 } else if (!strncasecmp(chan->language, "nl", 2)) {
09089 return vm_intro_nl(chan, vms);
09090 } else if (!strncasecmp(chan->language, "no", 2)) {
09091 return vm_intro_no(chan, vms);
09092 } else if (!strncasecmp(chan->language, "pl", 2)) {
09093 return vm_intro_pl(chan, vms);
09094 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09095 return vm_intro_pt_BR(chan, vms);
09096 } else if (!strncasecmp(chan->language, "pt", 2)) {
09097 return vm_intro_pt(chan, vms);
09098 } else if (!strncasecmp(chan->language, "ru", 2)) {
09099 return vm_intro_multilang(chan, vms, "n");
09100 } else if (!strncasecmp(chan->language, "se", 2)) {
09101 return vm_intro_se(chan, vms);
09102 } else if (!strncasecmp(chan->language, "ua", 2)) {
09103 return vm_intro_multilang(chan, vms, "n");
09104 } else if (!strncasecmp(chan->language, "vi", 2)) {
09105 return vm_intro_vi(chan, vms);
09106 } else if (!strncasecmp(chan->language, "zh", 2)) {
09107 return vm_intro_zh(chan, vms);
09108 } else {
09109 return vm_intro_en(chan, vms);
09110 }
09111 }
09112
09113 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09114 {
09115 int res = 0;
09116
09117 while (!res) {
09118 if (vms->starting) {
09119 if (vms->lastmsg > -1) {
09120 if (skipadvanced)
09121 res = ast_play_and_wait(chan, "vm-onefor-full");
09122 else
09123 res = ast_play_and_wait(chan, "vm-onefor");
09124 if (!res)
09125 res = vm_play_folder_name(chan, vms->vmbox);
09126 }
09127 if (!res) {
09128 if (skipadvanced)
09129 res = ast_play_and_wait(chan, "vm-opts-full");
09130 else
09131 res = ast_play_and_wait(chan, "vm-opts");
09132 }
09133 } else {
09134
09135 if (skipadvanced) {
09136 res = ast_play_and_wait(chan, "vm-onefor-full");
09137 if (!res)
09138 res = vm_play_folder_name(chan, vms->vmbox);
09139 res = ast_play_and_wait(chan, "vm-opts-full");
09140 }
09141
09142
09143
09144
09145
09146
09147 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09148 res = ast_play_and_wait(chan, "vm-prev");
09149 }
09150 if (!res && !skipadvanced)
09151 res = ast_play_and_wait(chan, "vm-advopts");
09152 if (!res)
09153 res = ast_play_and_wait(chan, "vm-repeat");
09154
09155
09156
09157
09158
09159
09160 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09161 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09162 res = ast_play_and_wait(chan, "vm-next");
09163 }
09164 if (!res) {
09165 int curmsg_deleted;
09166 #ifdef IMAP_STORAGE
09167 ast_mutex_lock(&vms->lock);
09168 #endif
09169 curmsg_deleted = vms->deleted[vms->curmsg];
09170 #ifdef IMAP_STORAGE
09171 ast_mutex_unlock(&vms->lock);
09172 #endif
09173 if (!curmsg_deleted) {
09174 res = ast_play_and_wait(chan, "vm-delete");
09175 } else {
09176 res = ast_play_and_wait(chan, "vm-undelete");
09177 }
09178 if (!res) {
09179 res = ast_play_and_wait(chan, "vm-toforward");
09180 }
09181 if (!res) {
09182 res = ast_play_and_wait(chan, "vm-savemessage");
09183 }
09184 }
09185 }
09186 if (!res) {
09187 res = ast_play_and_wait(chan, "vm-helpexit");
09188 }
09189 if (!res)
09190 res = ast_waitfordigit(chan, 6000);
09191 if (!res) {
09192 vms->repeats++;
09193 if (vms->repeats > 2) {
09194 res = 't';
09195 }
09196 }
09197 }
09198 return res;
09199 }
09200
09201 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09202 {
09203 int res = 0;
09204
09205 while (!res) {
09206 if (vms->lastmsg > -1) {
09207 res = ast_play_and_wait(chan, "vm-listen");
09208 if (!res)
09209 res = vm_play_folder_name(chan, vms->vmbox);
09210 if (!res)
09211 res = ast_play_and_wait(chan, "press");
09212 if (!res)
09213 res = ast_play_and_wait(chan, "digits/1");
09214 }
09215 if (!res)
09216 res = ast_play_and_wait(chan, "vm-opts");
09217 if (!res) {
09218 vms->starting = 0;
09219 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09220 }
09221 }
09222 return res;
09223 }
09224
09225 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09226 {
09227 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09228 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09229 } else {
09230 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09231 }
09232 }
09233
09234
09235 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09236 {
09237 int cmd = 0;
09238 int duration = 0;
09239 int tries = 0;
09240 char newpassword[80] = "";
09241 char newpassword2[80] = "";
09242 char prefile[PATH_MAX] = "";
09243 unsigned char buf[256];
09244 int bytes = 0;
09245
09246 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09247 if (ast_adsi_available(chan)) {
09248 bytes += adsi_logo(buf + bytes);
09249 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09250 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09251 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09252 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09253 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09254 }
09255
09256
09257 if (ast_test_flag(vmu, VM_FORCENAME)) {
09258 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09259 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09260 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09261 if (cmd < 0 || cmd == 't' || cmd == '#')
09262 return cmd;
09263 }
09264 }
09265
09266
09267 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09268 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09269 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09270 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09271 if (cmd < 0 || cmd == 't' || cmd == '#')
09272 return cmd;
09273 }
09274
09275 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09276 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09277 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09278 if (cmd < 0 || cmd == 't' || cmd == '#')
09279 return cmd;
09280 }
09281 }
09282
09283
09284
09285
09286
09287 for (;;) {
09288 newpassword[1] = '\0';
09289 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09290 if (cmd == '#')
09291 newpassword[0] = '\0';
09292 if (cmd < 0 || cmd == 't' || cmd == '#')
09293 return cmd;
09294 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09295 if (cmd < 0 || cmd == 't' || cmd == '#')
09296 return cmd;
09297 cmd = check_password(vmu, newpassword);
09298 if (cmd != 0) {
09299 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09300 cmd = ast_play_and_wait(chan, vm_invalid_password);
09301 } else {
09302 newpassword2[1] = '\0';
09303 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09304 if (cmd == '#')
09305 newpassword2[0] = '\0';
09306 if (cmd < 0 || cmd == 't' || cmd == '#')
09307 return cmd;
09308 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09309 if (cmd < 0 || cmd == 't' || cmd == '#')
09310 return cmd;
09311 if (!strcmp(newpassword, newpassword2))
09312 break;
09313 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09314 cmd = ast_play_and_wait(chan, vm_mismatch);
09315 }
09316 if (++tries == 3)
09317 return -1;
09318 if (cmd != 0) {
09319 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09320 }
09321 }
09322 if (pwdchange & PWDCHANGE_INTERNAL)
09323 vm_change_password(vmu, newpassword);
09324 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09325 vm_change_password_shell(vmu, newpassword);
09326
09327 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09328 cmd = ast_play_and_wait(chan, vm_passchanged);
09329
09330 return cmd;
09331 }
09332
09333 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09334 {
09335 int cmd = 0;
09336 int retries = 0;
09337 int duration = 0;
09338 char newpassword[80] = "";
09339 char newpassword2[80] = "";
09340 char prefile[PATH_MAX] = "";
09341 unsigned char buf[256];
09342 int bytes = 0;
09343
09344 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09345 if (ast_adsi_available(chan)) {
09346 bytes += adsi_logo(buf + bytes);
09347 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09348 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09349 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09350 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09351 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09352 }
09353 while ((cmd >= 0) && (cmd != 't')) {
09354 if (cmd)
09355 retries = 0;
09356 switch (cmd) {
09357 case '1':
09358 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09359 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09360 break;
09361 case '2':
09362 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09363 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09364 break;
09365 case '3':
09366 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09367 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09368 break;
09369 case '4':
09370 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09371 break;
09372 case '5':
09373 if (vmu->password[0] == '-') {
09374 cmd = ast_play_and_wait(chan, "vm-no");
09375 break;
09376 }
09377 newpassword[1] = '\0';
09378 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09379 if (cmd == '#')
09380 newpassword[0] = '\0';
09381 else {
09382 if (cmd < 0)
09383 break;
09384 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09385 break;
09386 }
09387 }
09388 cmd = check_password(vmu, newpassword);
09389 if (cmd != 0) {
09390 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09391 cmd = ast_play_and_wait(chan, vm_invalid_password);
09392 if (!cmd) {
09393 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09394 }
09395 break;
09396 }
09397 newpassword2[1] = '\0';
09398 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09399 if (cmd == '#')
09400 newpassword2[0] = '\0';
09401 else {
09402 if (cmd < 0)
09403 break;
09404
09405 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09406 break;
09407 }
09408 }
09409 if (strcmp(newpassword, newpassword2)) {
09410 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09411 cmd = ast_play_and_wait(chan, vm_mismatch);
09412 if (!cmd) {
09413 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09414 }
09415 break;
09416 }
09417
09418 if (pwdchange & PWDCHANGE_INTERNAL) {
09419 vm_change_password(vmu, newpassword);
09420 }
09421 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09422 vm_change_password_shell(vmu, newpassword);
09423 }
09424
09425 ast_debug(1, "User %s set password to %s of length %d\n",
09426 vms->username, newpassword, (int) strlen(newpassword));
09427 cmd = ast_play_and_wait(chan, vm_passchanged);
09428 break;
09429 case '*':
09430 cmd = 't';
09431 break;
09432 default:
09433 cmd = 0;
09434 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09435 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09436 if (ast_fileexists(prefile, NULL, NULL)) {
09437 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09438 }
09439 DISPOSE(prefile, -1);
09440 if (!cmd) {
09441 cmd = ast_play_and_wait(chan, "vm-options");
09442 }
09443 if (!cmd) {
09444 cmd = ast_waitfordigit(chan, 6000);
09445 }
09446 if (!cmd) {
09447 retries++;
09448 }
09449 if (retries > 3) {
09450 cmd = 't';
09451 }
09452 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09453 }
09454 }
09455 if (cmd == 't')
09456 cmd = 0;
09457 return cmd;
09458 }
09459
09460
09461
09462
09463
09464
09465
09466
09467
09468
09469
09470
09471
09472
09473
09474
09475
09476 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09477 {
09478 int cmd = 0;
09479 int retries = 0;
09480 int duration = 0;
09481 char prefile[PATH_MAX] = "";
09482 unsigned char buf[256];
09483 int bytes = 0;
09484
09485 if (ast_adsi_available(chan)) {
09486 bytes += adsi_logo(buf + bytes);
09487 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09488 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09489 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09490 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09491 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09492 }
09493
09494 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09495 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09496 while ((cmd >= 0) && (cmd != 't')) {
09497 if (cmd)
09498 retries = 0;
09499 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09500 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09501 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09502 if (cmd == -1) {
09503 break;
09504 }
09505 cmd = 't';
09506 } else {
09507 switch (cmd) {
09508 case '1':
09509 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09510 break;
09511 case '2':
09512 DELETE(prefile, -1, prefile, vmu);
09513 ast_play_and_wait(chan, "vm-tempremoved");
09514 cmd = 't';
09515 break;
09516 case '*':
09517 cmd = 't';
09518 break;
09519 default:
09520 cmd = ast_play_and_wait(chan,
09521 ast_fileexists(prefile, NULL, NULL) > 0 ?
09522 "vm-tempgreeting2" : "vm-tempgreeting");
09523 if (!cmd) {
09524 cmd = ast_waitfordigit(chan, 6000);
09525 }
09526 if (!cmd) {
09527 retries++;
09528 }
09529 if (retries > 3) {
09530 cmd = 't';
09531 }
09532 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09533 }
09534 }
09535 DISPOSE(prefile, -1);
09536 }
09537 if (cmd == 't')
09538 cmd = 0;
09539 return cmd;
09540 }
09541
09542
09543
09544
09545
09546
09547
09548
09549
09550 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09551 {
09552 int cmd = 0;
09553
09554 if (vms->lastmsg > -1) {
09555 cmd = play_message(chan, vmu, vms);
09556 } else {
09557 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09558 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09559 if (!cmd) {
09560 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09561 cmd = ast_play_and_wait(chan, vms->fn);
09562 }
09563 if (!cmd)
09564 cmd = ast_play_and_wait(chan, "vm-messages");
09565 } else {
09566 if (!cmd)
09567 cmd = ast_play_and_wait(chan, "vm-messages");
09568 if (!cmd) {
09569 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09570 cmd = ast_play_and_wait(chan, vms->fn);
09571 }
09572 }
09573 }
09574 return cmd;
09575 }
09576
09577
09578 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09579 {
09580 int cmd = 0;
09581
09582 if (vms->lastmsg > -1) {
09583 cmd = play_message(chan, vmu, vms);
09584 } else {
09585 if (!strcasecmp(vms->fn, "INBOX")) {
09586 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09587 } else {
09588 cmd = ast_play_and_wait(chan, "vm-nomessages");
09589 }
09590 }
09591 return cmd;
09592 }
09593
09594
09595
09596
09597
09598
09599
09600
09601
09602 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09603 {
09604 int cmd = 0;
09605
09606 if (vms->lastmsg > -1) {
09607 cmd = play_message(chan, vmu, vms);
09608 } else {
09609 cmd = ast_play_and_wait(chan, "vm-youhave");
09610 if (!cmd)
09611 cmd = ast_play_and_wait(chan, "vm-no");
09612 if (!cmd) {
09613 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09614 cmd = ast_play_and_wait(chan, vms->fn);
09615 }
09616 if (!cmd)
09617 cmd = ast_play_and_wait(chan, "vm-messages");
09618 }
09619 return cmd;
09620 }
09621
09622
09623
09624
09625
09626
09627
09628
09629
09630 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09631 {
09632 int cmd;
09633
09634 if (vms->lastmsg > -1) {
09635 cmd = play_message(chan, vmu, vms);
09636 } else {
09637 cmd = ast_play_and_wait(chan, "vm-no");
09638 if (!cmd)
09639 cmd = ast_play_and_wait(chan, "vm-message");
09640 if (!cmd) {
09641 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09642 cmd = ast_play_and_wait(chan, vms->fn);
09643 }
09644 }
09645 return cmd;
09646 }
09647
09648
09649
09650
09651
09652
09653
09654
09655
09656 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09657 {
09658 int cmd;
09659
09660 if (vms->lastmsg > -1) {
09661 cmd = play_message(chan, vmu, vms);
09662 } else {
09663 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09664 if (!cmd)
09665 cmd = ast_play_and_wait(chan, "vm-messages");
09666 if (!cmd) {
09667 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09668 cmd = ast_play_and_wait(chan, vms->fn);
09669 }
09670 }
09671 return cmd;
09672 }
09673
09674
09675
09676
09677
09678
09679
09680
09681
09682 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09683 {
09684 int cmd;
09685
09686 if (vms->lastmsg > -1) {
09687 cmd = play_message(chan, vmu, vms);
09688 } else {
09689 cmd = ast_play_and_wait(chan, "vm-no");
09690 if (!cmd) {
09691 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09692 cmd = ast_play_and_wait(chan, vms->fn);
09693 }
09694 if (!cmd)
09695 cmd = ast_play_and_wait(chan, "vm-messages");
09696 }
09697 return cmd;
09698 }
09699
09700
09701
09702
09703
09704
09705
09706
09707
09708 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09709 {
09710 int cmd;
09711
09712 if (vms->lastmsg > -1) {
09713 cmd = play_message(chan, vmu, vms);
09714 } else {
09715 cmd = ast_play_and_wait(chan, "vm-you");
09716 if (!cmd)
09717 cmd = ast_play_and_wait(chan, "vm-haveno");
09718 if (!cmd)
09719 cmd = ast_play_and_wait(chan, "vm-messages");
09720 if (!cmd) {
09721 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09722 cmd = ast_play_and_wait(chan, vms->fn);
09723 }
09724 }
09725 return cmd;
09726 }
09727
09728
09729
09730
09731
09732
09733
09734
09735
09736 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09737 {
09738 int cmd = 0;
09739
09740 if (vms->lastmsg > -1) {
09741 cmd = play_message(chan, vmu, vms);
09742 } else {
09743 cmd = ast_play_and_wait(chan, "vm-no");
09744 if (!cmd) {
09745 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09746 cmd = ast_play_and_wait(chan, vms->fn);
09747 }
09748 }
09749 return cmd;
09750 }
09751
09752
09753
09754
09755
09756
09757
09758
09759
09760
09761
09762
09763 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09764 {
09765 if (!strncasecmp(chan->language, "es", 2)) {
09766 return vm_browse_messages_es(chan, vms, vmu);
09767 } else if (!strncasecmp(chan->language, "gr", 2)) {
09768 return vm_browse_messages_gr(chan, vms, vmu);
09769 } else if (!strncasecmp(chan->language, "he", 2)) {
09770 return vm_browse_messages_he(chan, vms, vmu);
09771 } else if (!strncasecmp(chan->language, "it", 2)) {
09772 return vm_browse_messages_it(chan, vms, vmu);
09773 } else if (!strncasecmp(chan->language, "pt", 2)) {
09774 return vm_browse_messages_pt(chan, vms, vmu);
09775 } else if (!strncasecmp(chan->language, "vi", 2)) {
09776 return vm_browse_messages_vi(chan, vms, vmu);
09777 } else if (!strncasecmp(chan->language, "zh", 2)) {
09778 return vm_browse_messages_zh(chan, vms, vmu);
09779 } else {
09780 return vm_browse_messages_en(chan, vms, vmu);
09781 }
09782 }
09783
09784 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09785 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09786 int skipuser, int max_logins, int silent)
09787 {
09788 int useadsi = 0, valid = 0, logretries = 0;
09789 char password[AST_MAX_EXTENSION]="", *passptr;
09790 struct ast_vm_user vmus, *vmu = NULL;
09791
09792
09793 adsi_begin(chan, &useadsi);
09794 if (!skipuser && useadsi)
09795 adsi_login(chan);
09796 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09797 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09798 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09799 return -1;
09800 }
09801
09802
09803
09804 while (!valid && (logretries < max_logins)) {
09805
09806 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09807 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09808 return -1;
09809 }
09810 if (ast_strlen_zero(mailbox)) {
09811 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09812 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09813 } else {
09814 ast_verb(3, "Username not entered\n");
09815 return -1;
09816 }
09817 } else if (mailbox[0] == '*') {
09818
09819 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09820 if (ast_exists_extension(chan, chan->context, "a", 1,
09821 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09822 return -1;
09823 }
09824 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09825 mailbox[0] = '\0';
09826 }
09827
09828 if (useadsi)
09829 adsi_password(chan);
09830
09831 if (!ast_strlen_zero(prefix)) {
09832 char fullusername[80] = "";
09833 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09834 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09835 ast_copy_string(mailbox, fullusername, mailbox_size);
09836 }
09837
09838 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09839 vmu = find_user(&vmus, context, mailbox);
09840 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09841
09842 password[0] = '\0';
09843 } else {
09844 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09845 if (ast_streamfile(chan, vm_password, chan->language)) {
09846 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09847 return -1;
09848 }
09849 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09850 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09851 return -1;
09852 } else if (password[0] == '*') {
09853
09854 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09855 if (ast_exists_extension(chan, chan->context, "a", 1,
09856 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09857 mailbox[0] = '*';
09858 return -1;
09859 }
09860 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09861 mailbox[0] = '\0';
09862
09863 vmu = NULL;
09864 }
09865 }
09866
09867 if (vmu) {
09868 passptr = vmu->password;
09869 if (passptr[0] == '-') passptr++;
09870 }
09871 if (vmu && !strcmp(passptr, password))
09872 valid++;
09873 else {
09874 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09875 if (!ast_strlen_zero(prefix))
09876 mailbox[0] = '\0';
09877 }
09878 logretries++;
09879 if (!valid) {
09880 if (skipuser || logretries >= max_logins) {
09881 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09882 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09883 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09884 return -1;
09885 }
09886 } else {
09887 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09888 if (useadsi)
09889 adsi_login(chan);
09890 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09891 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09892 return -1;
09893 }
09894 }
09895 if (ast_waitstream(chan, ""))
09896 return -1;
09897 }
09898 }
09899 if (!valid && (logretries >= max_logins)) {
09900 ast_stopstream(chan);
09901 ast_play_and_wait(chan, "vm-goodbye");
09902 return -1;
09903 }
09904 if (vmu && !skipuser) {
09905 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09906 }
09907 return 0;
09908 }
09909
09910 static int vm_execmain(struct ast_channel *chan, const char *data)
09911 {
09912
09913
09914
09915 int res = -1;
09916 int cmd = 0;
09917 int valid = 0;
09918 char prefixstr[80] ="";
09919 char ext_context[256]="";
09920 int box;
09921 int useadsi = 0;
09922 int skipuser = 0;
09923 struct vm_state vms;
09924 struct ast_vm_user *vmu = NULL, vmus;
09925 char *context = NULL;
09926 int silentexit = 0;
09927 struct ast_flags flags = { 0 };
09928 signed char record_gain = 0;
09929 int play_auto = 0;
09930 int play_folder = 0;
09931 int in_urgent = 0;
09932 #ifdef IMAP_STORAGE
09933 int deleted = 0;
09934 #endif
09935
09936
09937 memset(&vms, 0, sizeof(vms));
09938
09939 vms.lastmsg = -1;
09940
09941 memset(&vmus, 0, sizeof(vmus));
09942
09943 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09944 if (chan->_state != AST_STATE_UP) {
09945 ast_debug(1, "Before ast_answer\n");
09946 ast_answer(chan);
09947 }
09948
09949 if (!ast_strlen_zero(data)) {
09950 char *opts[OPT_ARG_ARRAY_SIZE];
09951 char *parse;
09952 AST_DECLARE_APP_ARGS(args,
09953 AST_APP_ARG(argv0);
09954 AST_APP_ARG(argv1);
09955 );
09956
09957 parse = ast_strdupa(data);
09958
09959 AST_STANDARD_APP_ARGS(args, parse);
09960
09961 if (args.argc == 2) {
09962 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09963 return -1;
09964 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09965 int gain;
09966 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09967 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09968 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09969 return -1;
09970 } else {
09971 record_gain = (signed char) gain;
09972 }
09973 } else {
09974 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09975 }
09976 }
09977 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09978 play_auto = 1;
09979 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09980
09981 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09982 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09983 play_folder = -1;
09984 }
09985 } else {
09986 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09987 }
09988 } else {
09989 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09990 }
09991 if (play_folder > 9 || play_folder < 0) {
09992 ast_log(AST_LOG_WARNING,
09993 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09994 opts[OPT_ARG_PLAYFOLDER]);
09995 play_folder = 0;
09996 }
09997 }
09998 } else {
09999
10000 while (*(args.argv0)) {
10001 if (*(args.argv0) == 's')
10002 ast_set_flag(&flags, OPT_SILENT);
10003 else if (*(args.argv0) == 'p')
10004 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
10005 else
10006 break;
10007 (args.argv0)++;
10008 }
10009
10010 }
10011
10012 valid = ast_test_flag(&flags, OPT_SILENT);
10013
10014 if ((context = strchr(args.argv0, '@')))
10015 *context++ = '\0';
10016
10017 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10018 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10019 else
10020 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10021
10022 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10023 skipuser++;
10024 else
10025 valid = 0;
10026 }
10027
10028 if (!valid)
10029 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10030
10031 ast_debug(1, "After vm_authenticate\n");
10032
10033 if (vms.username[0] == '*') {
10034 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10035
10036
10037 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10038 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10039 res = 0;
10040 goto out;
10041 }
10042 }
10043
10044 if (!res) {
10045 valid = 1;
10046 if (!skipuser)
10047 vmu = &vmus;
10048 } else {
10049 res = 0;
10050 }
10051
10052
10053 adsi_begin(chan, &useadsi);
10054
10055 ast_test_suite_assert(valid);
10056 if (!valid) {
10057 goto out;
10058 }
10059 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10060
10061 #ifdef IMAP_STORAGE
10062 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10063 pthread_setspecific(ts_vmstate.key, &vms);
10064
10065 vms.interactive = 1;
10066 vms.updated = 1;
10067 if (vmu)
10068 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10069 vmstate_insert(&vms);
10070 init_vm_state(&vms);
10071 #endif
10072
10073
10074 if (!ast_strlen_zero(vmu->language))
10075 ast_string_field_set(chan, language, vmu->language);
10076
10077
10078 ast_debug(1, "Before open_mailbox\n");
10079 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10080 if (res < 0)
10081 goto out;
10082 vms.oldmessages = vms.lastmsg + 1;
10083 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10084
10085 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10086 if (res < 0)
10087 goto out;
10088 vms.newmessages = vms.lastmsg + 1;
10089 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10090
10091 in_urgent = 1;
10092 res = open_mailbox(&vms, vmu, 11);
10093 if (res < 0)
10094 goto out;
10095 vms.urgentmessages = vms.lastmsg + 1;
10096 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10097
10098
10099 if (play_auto) {
10100 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10101 if (vms.urgentmessages) {
10102 in_urgent = 1;
10103 res = open_mailbox(&vms, vmu, 11);
10104 } else {
10105 in_urgent = 0;
10106 res = open_mailbox(&vms, vmu, play_folder);
10107 }
10108 if (res < 0)
10109 goto out;
10110
10111
10112 if (vms.lastmsg == -1) {
10113 in_urgent = 0;
10114 cmd = vm_browse_messages(chan, &vms, vmu);
10115 res = 0;
10116 goto out;
10117 }
10118 } else {
10119 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10120
10121 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10122 in_urgent = 0;
10123 play_folder = 1;
10124 if (res < 0)
10125 goto out;
10126 } else if (!vms.urgentmessages && vms.newmessages) {
10127
10128 in_urgent = 0;
10129 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10130 if (res < 0)
10131 goto out;
10132 }
10133 }
10134
10135 if (useadsi)
10136 adsi_status(chan, &vms);
10137 res = 0;
10138
10139
10140 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10141 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10142 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10143 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10144 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10145 if ((cmd == 't') || (cmd == '#')) {
10146
10147 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10148 res = 0;
10149 goto out;
10150 } else if (cmd < 0) {
10151
10152 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10153 res = -1;
10154 goto out;
10155 }
10156 }
10157 #ifdef IMAP_STORAGE
10158 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10159 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10160 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10161 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10162 }
10163 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10164 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10165 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10166 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10167 }
10168 #endif
10169
10170 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10171 if (play_auto) {
10172 cmd = '1';
10173 } else {
10174 cmd = vm_intro(chan, vmu, &vms);
10175 }
10176 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10177
10178 vms.repeats = 0;
10179 vms.starting = 1;
10180 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10181
10182 switch (cmd) {
10183 case '1':
10184 vms.curmsg = 0;
10185
10186 case '5':
10187 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10188 cmd = vm_browse_messages(chan, &vms, vmu);
10189 break;
10190 case '2':
10191 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10192 if (useadsi)
10193 adsi_folders(chan, 0, "Change to folder...");
10194
10195 cmd = get_folder2(chan, "vm-changeto", 0);
10196 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10197 if (cmd == '#') {
10198 cmd = 0;
10199 } else if (cmd > 0) {
10200 cmd = cmd - '0';
10201 res = close_mailbox(&vms, vmu);
10202 if (res == ERROR_LOCK_PATH)
10203 goto out;
10204
10205 if (cmd != 11) in_urgent = 0;
10206 res = open_mailbox(&vms, vmu, cmd);
10207 if (res < 0)
10208 goto out;
10209 play_folder = cmd;
10210 cmd = 0;
10211 }
10212 if (useadsi)
10213 adsi_status2(chan, &vms);
10214
10215 if (!cmd) {
10216 cmd = vm_play_folder_name(chan, vms.vmbox);
10217 }
10218
10219 vms.starting = 1;
10220 vms.curmsg = 0;
10221 break;
10222 case '3':
10223 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10224 cmd = 0;
10225 vms.repeats = 0;
10226 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10227 switch (cmd) {
10228 case '1':
10229 if (vms.lastmsg > -1 && !vms.starting) {
10230 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10231 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10232 res = cmd;
10233 goto out;
10234 }
10235 } else {
10236 cmd = ast_play_and_wait(chan, "vm-sorry");
10237 }
10238 cmd = 't';
10239 break;
10240 case '2':
10241 if (!vms.starting)
10242 ast_verb(3, "Callback Requested\n");
10243 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10244 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10245 if (cmd == 9) {
10246 silentexit = 1;
10247 goto out;
10248 } else if (cmd == ERROR_LOCK_PATH) {
10249 res = cmd;
10250 goto out;
10251 }
10252 } else {
10253 cmd = ast_play_and_wait(chan, "vm-sorry");
10254 }
10255 cmd = 't';
10256 break;
10257 case '3':
10258 if (vms.lastmsg > -1 && !vms.starting) {
10259 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10260 if (cmd == ERROR_LOCK_PATH) {
10261 res = cmd;
10262 goto out;
10263 }
10264 } else {
10265 cmd = ast_play_and_wait(chan, "vm-sorry");
10266 }
10267 cmd = 't';
10268 break;
10269 case '4':
10270 if (!ast_strlen_zero(vmu->dialout)) {
10271 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10272 if (cmd == 9) {
10273 silentexit = 1;
10274 goto out;
10275 }
10276 } else {
10277 cmd = ast_play_and_wait(chan, "vm-sorry");
10278 }
10279 cmd = 't';
10280 break;
10281
10282 case '5':
10283 if (ast_test_flag(vmu, VM_SVMAIL)) {
10284 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10285 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10286 res = cmd;
10287 goto out;
10288 }
10289 } else {
10290 cmd = ast_play_and_wait(chan, "vm-sorry");
10291 }
10292 cmd = 't';
10293 break;
10294
10295 case '*':
10296 cmd = 't';
10297 break;
10298
10299 default:
10300 cmd = 0;
10301 if (!vms.starting) {
10302 cmd = ast_play_and_wait(chan, "vm-toreply");
10303 }
10304 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10305 cmd = ast_play_and_wait(chan, "vm-tocallback");
10306 }
10307 if (!cmd && !vms.starting) {
10308 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10309 }
10310 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10311 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10312 }
10313 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10314 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10315 }
10316 if (!cmd) {
10317 cmd = ast_play_and_wait(chan, "vm-starmain");
10318 }
10319 if (!cmd) {
10320 cmd = ast_waitfordigit(chan, 6000);
10321 }
10322 if (!cmd) {
10323 vms.repeats++;
10324 }
10325 if (vms.repeats > 3) {
10326 cmd = 't';
10327 }
10328 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10329 }
10330 }
10331 if (cmd == 't') {
10332 cmd = 0;
10333 vms.repeats = 0;
10334 }
10335 break;
10336 case '4':
10337 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10338 if (vms.curmsg > 0) {
10339 vms.curmsg--;
10340 cmd = play_message(chan, vmu, &vms);
10341 } else {
10342
10343
10344
10345
10346 if (in_urgent == 0 && vms.urgentmessages > 0) {
10347
10348 in_urgent = 1;
10349 res = close_mailbox(&vms, vmu);
10350 if (res == ERROR_LOCK_PATH)
10351 goto out;
10352 res = open_mailbox(&vms, vmu, 11);
10353 if (res < 0)
10354 goto out;
10355 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10356 vms.curmsg = vms.lastmsg;
10357 if (vms.lastmsg < 0) {
10358 cmd = ast_play_and_wait(chan, "vm-nomore");
10359 }
10360 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10361 vms.curmsg = vms.lastmsg;
10362 cmd = play_message(chan, vmu, &vms);
10363 } else {
10364 cmd = ast_play_and_wait(chan, "vm-nomore");
10365 }
10366 }
10367 break;
10368 case '6':
10369 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10370 if (vms.curmsg < vms.lastmsg) {
10371 vms.curmsg++;
10372 cmd = play_message(chan, vmu, &vms);
10373 } else {
10374 if (in_urgent && vms.newmessages > 0) {
10375
10376
10377
10378
10379 in_urgent = 0;
10380 res = close_mailbox(&vms, vmu);
10381 if (res == ERROR_LOCK_PATH)
10382 goto out;
10383 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10384 if (res < 0)
10385 goto out;
10386 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10387 vms.curmsg = -1;
10388 if (vms.lastmsg < 0) {
10389 cmd = ast_play_and_wait(chan, "vm-nomore");
10390 }
10391 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10392 vms.curmsg = 0;
10393 cmd = play_message(chan, vmu, &vms);
10394 } else {
10395 cmd = ast_play_and_wait(chan, "vm-nomore");
10396 }
10397 }
10398 break;
10399 case '7':
10400 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10401 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10402 if (useadsi)
10403 adsi_delete(chan, &vms);
10404 if (vms.deleted[vms.curmsg]) {
10405 if (play_folder == 0) {
10406 if (in_urgent) {
10407 vms.urgentmessages--;
10408 } else {
10409 vms.newmessages--;
10410 }
10411 }
10412 else if (play_folder == 1)
10413 vms.oldmessages--;
10414 cmd = ast_play_and_wait(chan, "vm-deleted");
10415 } else {
10416 if (play_folder == 0) {
10417 if (in_urgent) {
10418 vms.urgentmessages++;
10419 } else {
10420 vms.newmessages++;
10421 }
10422 }
10423 else if (play_folder == 1)
10424 vms.oldmessages++;
10425 cmd = ast_play_and_wait(chan, "vm-undeleted");
10426 }
10427 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10428 if (vms.curmsg < vms.lastmsg) {
10429 vms.curmsg++;
10430 cmd = play_message(chan, vmu, &vms);
10431 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10432 vms.curmsg = 0;
10433 cmd = play_message(chan, vmu, &vms);
10434 } else {
10435
10436
10437
10438
10439 if (in_urgent == 1) {
10440
10441 in_urgent = 0;
10442 res = close_mailbox(&vms, vmu);
10443 if (res == ERROR_LOCK_PATH)
10444 goto out;
10445 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10446 if (res < 0)
10447 goto out;
10448 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10449 vms.curmsg = -1;
10450 if (vms.lastmsg < 0) {
10451 cmd = ast_play_and_wait(chan, "vm-nomore");
10452 }
10453 } else {
10454 cmd = ast_play_and_wait(chan, "vm-nomore");
10455 }
10456 }
10457 }
10458 } else
10459 cmd = 0;
10460 #ifdef IMAP_STORAGE
10461 deleted = 1;
10462 #endif
10463 break;
10464
10465 case '8':
10466 if (vms.lastmsg > -1) {
10467 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10468 if (cmd == ERROR_LOCK_PATH) {
10469 res = cmd;
10470 goto out;
10471 }
10472 } else {
10473
10474
10475
10476
10477 if (in_urgent == 1 && vms.newmessages > 0) {
10478
10479 in_urgent = 0;
10480 res = close_mailbox(&vms, vmu);
10481 if (res == ERROR_LOCK_PATH)
10482 goto out;
10483 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10484 if (res < 0)
10485 goto out;
10486 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10487 vms.curmsg = -1;
10488 if (vms.lastmsg < 0) {
10489 cmd = ast_play_and_wait(chan, "vm-nomore");
10490 }
10491 } else {
10492 cmd = ast_play_and_wait(chan, "vm-nomore");
10493 }
10494 }
10495 break;
10496 case '9':
10497 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10498 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10499
10500 cmd = 0;
10501 break;
10502 }
10503 if (useadsi)
10504 adsi_folders(chan, 1, "Save to folder...");
10505 cmd = get_folder2(chan, "vm-savefolder", 1);
10506 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10507 box = 0;
10508 if (cmd == '#') {
10509 cmd = 0;
10510 break;
10511 } else if (cmd > 0) {
10512 box = cmd = cmd - '0';
10513 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10514 if (cmd == ERROR_LOCK_PATH) {
10515 res = cmd;
10516 goto out;
10517 #ifndef IMAP_STORAGE
10518 } else if (!cmd) {
10519 vms.deleted[vms.curmsg] = 1;
10520 #endif
10521 } else {
10522 vms.deleted[vms.curmsg] = 0;
10523 vms.heard[vms.curmsg] = 0;
10524 }
10525 }
10526 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10527 if (useadsi)
10528 adsi_message(chan, &vms);
10529 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10530 if (!cmd) {
10531 cmd = ast_play_and_wait(chan, "vm-message");
10532 if (!cmd)
10533 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10534 if (!cmd)
10535 cmd = ast_play_and_wait(chan, "vm-savedto");
10536 if (!cmd)
10537 cmd = vm_play_folder_name(chan, vms.fn);
10538 } else {
10539 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10540 }
10541 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10542 if (vms.curmsg < vms.lastmsg) {
10543 vms.curmsg++;
10544 cmd = play_message(chan, vmu, &vms);
10545 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10546 vms.curmsg = 0;
10547 cmd = play_message(chan, vmu, &vms);
10548 } else {
10549
10550
10551
10552
10553 if (in_urgent == 1 && vms.newmessages > 0) {
10554
10555 in_urgent = 0;
10556 res = close_mailbox(&vms, vmu);
10557 if (res == ERROR_LOCK_PATH)
10558 goto out;
10559 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10560 if (res < 0)
10561 goto out;
10562 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10563 vms.curmsg = -1;
10564 if (vms.lastmsg < 0) {
10565 cmd = ast_play_and_wait(chan, "vm-nomore");
10566 }
10567 } else {
10568 cmd = ast_play_and_wait(chan, "vm-nomore");
10569 }
10570 }
10571 }
10572 break;
10573 case '*':
10574 if (!vms.starting) {
10575 cmd = ast_play_and_wait(chan, "vm-onefor");
10576 if (!strncasecmp(chan->language, "he", 2)) {
10577 cmd = ast_play_and_wait(chan, "vm-for");
10578 }
10579 if (!cmd)
10580 cmd = vm_play_folder_name(chan, vms.vmbox);
10581 if (!cmd)
10582 cmd = ast_play_and_wait(chan, "vm-opts");
10583 if (!cmd)
10584 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10585 } else
10586 cmd = 0;
10587 break;
10588 case '0':
10589 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10590 if (useadsi)
10591 adsi_status(chan, &vms);
10592 break;
10593 default:
10594 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10595 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10596 break;
10597 }
10598 }
10599 if ((cmd == 't') || (cmd == '#')) {
10600
10601 res = 0;
10602 } else {
10603
10604 res = -1;
10605 }
10606
10607 out:
10608 if (res > -1) {
10609 ast_stopstream(chan);
10610 adsi_goodbye(chan);
10611 if (valid && res != OPERATOR_EXIT) {
10612 if (silentexit)
10613 res = ast_play_and_wait(chan, "vm-dialout");
10614 else
10615 res = ast_play_and_wait(chan, "vm-goodbye");
10616 }
10617 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10618 res = 0;
10619 }
10620 if (useadsi)
10621 ast_adsi_unload_session(chan);
10622 }
10623 if (vmu)
10624 close_mailbox(&vms, vmu);
10625 if (valid) {
10626 int new = 0, old = 0, urgent = 0;
10627 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10628 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10629
10630 run_externnotify(vmu->context, vmu->mailbox, NULL);
10631 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10632 queue_mwi_event(ext_context, urgent, new, old);
10633 }
10634 #ifdef IMAP_STORAGE
10635
10636 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10637 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10638 ast_mutex_lock(&vms.lock);
10639 #ifdef HAVE_IMAP_TK2006
10640 if (LEVELUIDPLUS (vms.mailstream)) {
10641 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10642 } else
10643 #endif
10644 mail_expunge(vms.mailstream);
10645 ast_mutex_unlock(&vms.lock);
10646 }
10647
10648
10649 if (vmu) {
10650 vmstate_delete(&vms);
10651 }
10652 #endif
10653 if (vmu)
10654 free_user(vmu);
10655
10656 #ifdef IMAP_STORAGE
10657 pthread_setspecific(ts_vmstate.key, NULL);
10658 #endif
10659 return res;
10660 }
10661
10662 static int vm_exec(struct ast_channel *chan, const char *data)
10663 {
10664 int res = 0;
10665 char *tmp;
10666 struct leave_vm_options leave_options;
10667 struct ast_flags flags = { 0 };
10668 char *opts[OPT_ARG_ARRAY_SIZE];
10669 AST_DECLARE_APP_ARGS(args,
10670 AST_APP_ARG(argv0);
10671 AST_APP_ARG(argv1);
10672 );
10673
10674 memset(&leave_options, 0, sizeof(leave_options));
10675
10676 if (chan->_state != AST_STATE_UP)
10677 ast_answer(chan);
10678
10679 if (!ast_strlen_zero(data)) {
10680 tmp = ast_strdupa(data);
10681 AST_STANDARD_APP_ARGS(args, tmp);
10682 if (args.argc == 2) {
10683 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10684 return -1;
10685 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10686 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10687 int gain;
10688
10689 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10690 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10691 return -1;
10692 } else {
10693 leave_options.record_gain = (signed char) gain;
10694 }
10695 }
10696 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10697 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10698 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10699 }
10700 }
10701 } else {
10702 char temp[256];
10703 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10704 if (res < 0)
10705 return res;
10706 if (ast_strlen_zero(temp))
10707 return 0;
10708 args.argv0 = ast_strdupa(temp);
10709 }
10710
10711 res = leave_voicemail(chan, args.argv0, &leave_options);
10712 if (res == 't') {
10713 ast_play_and_wait(chan, "vm-goodbye");
10714 res = 0;
10715 }
10716
10717 if (res == OPERATOR_EXIT) {
10718 res = 0;
10719 }
10720
10721 if (res == ERROR_LOCK_PATH) {
10722 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10723 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10724 res = 0;
10725 }
10726
10727 return res;
10728 }
10729
10730 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10731 {
10732 struct ast_vm_user *vmu;
10733
10734 if (!ast_strlen_zero(box) && box[0] == '*') {
10735 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10736 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10737 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10738 "\n\tand will be ignored.\n", box, context);
10739 return NULL;
10740 }
10741
10742 AST_LIST_TRAVERSE(&users, vmu, list) {
10743 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10744 if (strcasecmp(vmu->context, context)) {
10745 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10746 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10747 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10748 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10749 }
10750 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10751 return NULL;
10752 }
10753 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10754 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10755 return NULL;
10756 }
10757 }
10758
10759 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10760 return NULL;
10761
10762 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10763 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10764
10765 AST_LIST_INSERT_TAIL(&users, vmu, list);
10766
10767 return vmu;
10768 }
10769
10770 static int append_mailbox(const char *context, const char *box, const char *data)
10771 {
10772
10773 char *tmp;
10774 char *stringp;
10775 char *s;
10776 struct ast_vm_user *vmu;
10777 char *mailbox_full;
10778 int new = 0, old = 0, urgent = 0;
10779 char secretfn[PATH_MAX] = "";
10780
10781 tmp = ast_strdupa(data);
10782
10783 if (!(vmu = find_or_create(context, box)))
10784 return -1;
10785
10786 populate_defaults(vmu);
10787
10788 stringp = tmp;
10789 if ((s = strsep(&stringp, ","))) {
10790 if (!ast_strlen_zero(s) && s[0] == '*') {
10791 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10792 "\n\tmust be reset in voicemail.conf.\n", box);
10793 }
10794
10795 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10796 }
10797 if (stringp && (s = strsep(&stringp, ","))) {
10798 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10799 }
10800 if (stringp && (s = strsep(&stringp, ","))) {
10801 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10802 }
10803 if (stringp && (s = strsep(&stringp, ","))) {
10804 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10805 }
10806 if (stringp && (s = strsep(&stringp, ","))) {
10807 apply_options(vmu, s);
10808 }
10809
10810 switch (vmu->passwordlocation) {
10811 case OPT_PWLOC_SPOOLDIR:
10812 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10813 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10814 }
10815
10816 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10817 strcpy(mailbox_full, box);
10818 strcat(mailbox_full, "@");
10819 strcat(mailbox_full, context);
10820
10821 inboxcount2(mailbox_full, &urgent, &new, &old);
10822 queue_mwi_event(mailbox_full, urgent, new, old);
10823
10824 return 0;
10825 }
10826
10827 AST_TEST_DEFINE(test_voicemail_vmuser)
10828 {
10829 int res = 0;
10830 struct ast_vm_user *vmu;
10831
10832 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10833 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10834 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10835 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10836 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10837 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10838 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10839 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10840 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10841 #ifdef IMAP_STORAGE
10842 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10843 "imapfolder=INBOX|imapvmshareid=6000";
10844 #endif
10845
10846 switch (cmd) {
10847 case TEST_INIT:
10848 info->name = "vmuser";
10849 info->category = "/apps/app_voicemail/";
10850 info->summary = "Vmuser unit test";
10851 info->description =
10852 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10853 return AST_TEST_NOT_RUN;
10854 case TEST_EXECUTE:
10855 break;
10856 }
10857
10858 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10859 return AST_TEST_NOT_RUN;
10860 }
10861 ast_set_flag(vmu, VM_ALLOCED);
10862 populate_defaults(vmu);
10863
10864 apply_options(vmu, options_string);
10865
10866 if (!ast_test_flag(vmu, VM_ATTACH)) {
10867 ast_test_status_update(test, "Parse failure for attach option\n");
10868 res = 1;
10869 }
10870 if (strcasecmp(vmu->attachfmt, "wav49")) {
10871 ast_test_status_update(test, "Parse failure for attachftm option\n");
10872 res = 1;
10873 }
10874 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10875 ast_test_status_update(test, "Parse failure for serveremail option\n");
10876 res = 1;
10877 }
10878 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10879 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10880 res = 1;
10881 }
10882 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10883 ast_test_status_update(test, "Parse failure for emailbody option\n");
10884 res = 1;
10885 }
10886 if (strcasecmp(vmu->zonetag, "central")) {
10887 ast_test_status_update(test, "Parse failure for tz option\n");
10888 res = 1;
10889 }
10890 if (!ast_test_flag(vmu, VM_DELETE)) {
10891 ast_test_status_update(test, "Parse failure for delete option\n");
10892 res = 1;
10893 }
10894 if (!ast_test_flag(vmu, VM_SAYCID)) {
10895 ast_test_status_update(test, "Parse failure for saycid option\n");
10896 res = 1;
10897 }
10898 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10899 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10900 res = 1;
10901 }
10902 if (!ast_test_flag(vmu, VM_REVIEW)) {
10903 ast_test_status_update(test, "Parse failure for review option\n");
10904 res = 1;
10905 }
10906 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10907 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10908 res = 1;
10909 }
10910 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10911 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10912 res = 1;
10913 }
10914 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10915 ast_test_status_update(test, "Parse failure for operator option\n");
10916 res = 1;
10917 }
10918 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10919 ast_test_status_update(test, "Parse failure for envelope option\n");
10920 res = 1;
10921 }
10922 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10923 ast_test_status_update(test, "Parse failure for moveheard option\n");
10924 res = 1;
10925 }
10926 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10927 ast_test_status_update(test, "Parse failure for sayduration option\n");
10928 res = 1;
10929 }
10930 if (vmu->saydurationm != 5) {
10931 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10932 res = 1;
10933 }
10934 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10935 ast_test_status_update(test, "Parse failure for forcename option\n");
10936 res = 1;
10937 }
10938 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10939 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10940 res = 1;
10941 }
10942 if (strcasecmp(vmu->callback, "somecontext")) {
10943 ast_test_status_update(test, "Parse failure for callbacks option\n");
10944 res = 1;
10945 }
10946 if (strcasecmp(vmu->dialout, "somecontext2")) {
10947 ast_test_status_update(test, "Parse failure for dialout option\n");
10948 res = 1;
10949 }
10950 if (strcasecmp(vmu->exit, "somecontext3")) {
10951 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10952 res = 1;
10953 }
10954 if (vmu->minsecs != 10) {
10955 ast_test_status_update(test, "Parse failure for minsecs option\n");
10956 res = 1;
10957 }
10958 if (vmu->maxsecs != 100) {
10959 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10960 res = 1;
10961 }
10962 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10963 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10964 res = 1;
10965 }
10966 if (vmu->maxdeletedmsg != 50) {
10967 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10968 res = 1;
10969 }
10970 if (vmu->volgain != 1.3) {
10971 ast_test_status_update(test, "Parse failure for volgain option\n");
10972 res = 1;
10973 }
10974 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10975 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10976 res = 1;
10977 }
10978 #ifdef IMAP_STORAGE
10979 apply_options(vmu, option_string2);
10980
10981 if (strcasecmp(vmu->imapuser, "imapuser")) {
10982 ast_test_status_update(test, "Parse failure for imapuser option\n");
10983 res = 1;
10984 }
10985 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10986 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10987 res = 1;
10988 }
10989 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10990 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10991 res = 1;
10992 }
10993 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10994 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10995 res = 1;
10996 }
10997 #endif
10998
10999 free_user(vmu);
11000 return res ? AST_TEST_FAIL : AST_TEST_PASS;
11001 }
11002
11003 static int vm_box_exists(struct ast_channel *chan, const char *data)
11004 {
11005 struct ast_vm_user svm;
11006 char *context, *box;
11007 AST_DECLARE_APP_ARGS(args,
11008 AST_APP_ARG(mbox);
11009 AST_APP_ARG(options);
11010 );
11011 static int dep_warning = 0;
11012
11013 if (ast_strlen_zero(data)) {
11014 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
11015 return -1;
11016 }
11017
11018 if (!dep_warning) {
11019 dep_warning = 1;
11020 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
11021 }
11022
11023 box = ast_strdupa(data);
11024
11025 AST_STANDARD_APP_ARGS(args, box);
11026
11027 if (args.options) {
11028 }
11029
11030 if ((context = strchr(args.mbox, '@'))) {
11031 *context = '\0';
11032 context++;
11033 }
11034
11035 if (find_user(&svm, context, args.mbox)) {
11036 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11037 } else
11038 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11039
11040 return 0;
11041 }
11042
11043 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11044 {
11045 struct ast_vm_user svm;
11046 AST_DECLARE_APP_ARGS(arg,
11047 AST_APP_ARG(mbox);
11048 AST_APP_ARG(context);
11049 );
11050
11051 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11052
11053 if (ast_strlen_zero(arg.mbox)) {
11054 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11055 return -1;
11056 }
11057
11058 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11059 return 0;
11060 }
11061
11062 static struct ast_custom_function mailbox_exists_acf = {
11063 .name = "MAILBOX_EXISTS",
11064 .read = acf_mailbox_exists,
11065 };
11066
11067 static int vmauthenticate(struct ast_channel *chan, const char *data)
11068 {
11069 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11070 struct ast_vm_user vmus;
11071 char *options = NULL;
11072 int silent = 0, skipuser = 0;
11073 int res = -1;
11074
11075 if (data) {
11076 s = ast_strdupa(data);
11077 user = strsep(&s, ",");
11078 options = strsep(&s, ",");
11079 if (user) {
11080 s = user;
11081 user = strsep(&s, "@");
11082 context = strsep(&s, "");
11083 if (!ast_strlen_zero(user))
11084 skipuser++;
11085 ast_copy_string(mailbox, user, sizeof(mailbox));
11086 }
11087 }
11088
11089 if (options) {
11090 silent = (strchr(options, 's')) != NULL;
11091 }
11092
11093 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11094 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11095 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11096 ast_play_and_wait(chan, "auth-thankyou");
11097 res = 0;
11098 } else if (mailbox[0] == '*') {
11099
11100 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11101 res = 0;
11102 }
11103 }
11104
11105 return res;
11106 }
11107
11108 static char *show_users_realtime(int fd, const char *context)
11109 {
11110 struct ast_config *cfg;
11111 const char *cat = NULL;
11112
11113 if (!(cfg = ast_load_realtime_multientry("voicemail",
11114 "context", context, SENTINEL))) {
11115 return CLI_FAILURE;
11116 }
11117
11118 ast_cli(fd,
11119 "\n"
11120 "=============================================================\n"
11121 "=== Configured Voicemail Users ==============================\n"
11122 "=============================================================\n"
11123 "===\n");
11124
11125 while ((cat = ast_category_browse(cfg, cat))) {
11126 struct ast_variable *var = NULL;
11127 ast_cli(fd,
11128 "=== Mailbox ...\n"
11129 "===\n");
11130 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11131 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11132 ast_cli(fd,
11133 "===\n"
11134 "=== ---------------------------------------------------------\n"
11135 "===\n");
11136 }
11137
11138 ast_cli(fd,
11139 "=============================================================\n"
11140 "\n");
11141
11142 ast_config_destroy(cfg);
11143
11144 return CLI_SUCCESS;
11145 }
11146
11147 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11148 {
11149 int which = 0;
11150 int wordlen;
11151 struct ast_vm_user *vmu;
11152 const char *context = "";
11153
11154
11155 if (pos > 4)
11156 return NULL;
11157 if (pos == 3)
11158 return (state == 0) ? ast_strdup("for") : NULL;
11159 wordlen = strlen(word);
11160 AST_LIST_TRAVERSE(&users, vmu, list) {
11161 if (!strncasecmp(word, vmu->context, wordlen)) {
11162 if (context && strcmp(context, vmu->context) && ++which > state)
11163 return ast_strdup(vmu->context);
11164
11165 context = vmu->context;
11166 }
11167 }
11168 return NULL;
11169 }
11170
11171
11172 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11173 {
11174 struct ast_vm_user *vmu;
11175 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11176 const char *context = NULL;
11177 int users_counter = 0;
11178
11179 switch (cmd) {
11180 case CLI_INIT:
11181 e->command = "voicemail show users";
11182 e->usage =
11183 "Usage: voicemail show users [for <context>]\n"
11184 " Lists all mailboxes currently set up\n";
11185 return NULL;
11186 case CLI_GENERATE:
11187 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11188 }
11189
11190 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11191 return CLI_SHOWUSAGE;
11192 if (a->argc == 5) {
11193 if (strcmp(a->argv[3],"for"))
11194 return CLI_SHOWUSAGE;
11195 context = a->argv[4];
11196 }
11197
11198 if (ast_check_realtime("voicemail")) {
11199 if (!context) {
11200 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11201 return CLI_SHOWUSAGE;
11202 }
11203 return show_users_realtime(a->fd, context);
11204 }
11205
11206 AST_LIST_LOCK(&users);
11207 if (AST_LIST_EMPTY(&users)) {
11208 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11209 AST_LIST_UNLOCK(&users);
11210 return CLI_FAILURE;
11211 }
11212 if (!context) {
11213 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11214 } else {
11215 int count = 0;
11216 AST_LIST_TRAVERSE(&users, vmu, list) {
11217 if (!strcmp(context, vmu->context)) {
11218 count++;
11219 break;
11220 }
11221 }
11222 if (count) {
11223 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11224 } else {
11225 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11226 AST_LIST_UNLOCK(&users);
11227 return CLI_FAILURE;
11228 }
11229 }
11230 AST_LIST_TRAVERSE(&users, vmu, list) {
11231 int newmsgs = 0, oldmsgs = 0;
11232 char count[12], tmp[256] = "";
11233
11234 if (!context || !strcmp(context, vmu->context)) {
11235 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11236 inboxcount(tmp, &newmsgs, &oldmsgs);
11237 snprintf(count, sizeof(count), "%d", newmsgs);
11238 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11239 users_counter++;
11240 }
11241 }
11242 AST_LIST_UNLOCK(&users);
11243 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11244 return CLI_SUCCESS;
11245 }
11246
11247
11248 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11249 {
11250 struct vm_zone *zone;
11251 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11252 char *res = CLI_SUCCESS;
11253
11254 switch (cmd) {
11255 case CLI_INIT:
11256 e->command = "voicemail show zones";
11257 e->usage =
11258 "Usage: voicemail show zones\n"
11259 " Lists zone message formats\n";
11260 return NULL;
11261 case CLI_GENERATE:
11262 return NULL;
11263 }
11264
11265 if (a->argc != 3)
11266 return CLI_SHOWUSAGE;
11267
11268 AST_LIST_LOCK(&zones);
11269 if (!AST_LIST_EMPTY(&zones)) {
11270 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11271 AST_LIST_TRAVERSE(&zones, zone, list) {
11272 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11273 }
11274 } else {
11275 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11276 res = CLI_FAILURE;
11277 }
11278 AST_LIST_UNLOCK(&zones);
11279
11280 return res;
11281 }
11282
11283
11284 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11285 {
11286 switch (cmd) {
11287 case CLI_INIT:
11288 e->command = "voicemail reload";
11289 e->usage =
11290 "Usage: voicemail reload\n"
11291 " Reload voicemail configuration\n";
11292 return NULL;
11293 case CLI_GENERATE:
11294 return NULL;
11295 }
11296
11297 if (a->argc != 2)
11298 return CLI_SHOWUSAGE;
11299
11300 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11301 load_config(1);
11302
11303 return CLI_SUCCESS;
11304 }
11305
11306 static struct ast_cli_entry cli_voicemail[] = {
11307 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11308 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11309 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11310 };
11311
11312 #ifdef IMAP_STORAGE
11313 #define DATA_EXPORT_VM_USERS(USER) \
11314 USER(ast_vm_user, context, AST_DATA_STRING) \
11315 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11316 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11317 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11318 USER(ast_vm_user, email, AST_DATA_STRING) \
11319 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11320 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11321 USER(ast_vm_user, pager, AST_DATA_STRING) \
11322 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11323 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11324 USER(ast_vm_user, language, AST_DATA_STRING) \
11325 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11326 USER(ast_vm_user, callback, AST_DATA_STRING) \
11327 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11328 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11329 USER(ast_vm_user, exit, AST_DATA_STRING) \
11330 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11331 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11332 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11333 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11334 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11335 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11336 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11337 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11338 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11339 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11340 #else
11341 #define DATA_EXPORT_VM_USERS(USER) \
11342 USER(ast_vm_user, context, AST_DATA_STRING) \
11343 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11344 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11345 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11346 USER(ast_vm_user, email, AST_DATA_STRING) \
11347 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11348 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11349 USER(ast_vm_user, pager, AST_DATA_STRING) \
11350 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11351 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11352 USER(ast_vm_user, language, AST_DATA_STRING) \
11353 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11354 USER(ast_vm_user, callback, AST_DATA_STRING) \
11355 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11356 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11357 USER(ast_vm_user, exit, AST_DATA_STRING) \
11358 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11359 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11360 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11361 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11362 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11363 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11364 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11365 #endif
11366
11367 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11368
11369 #define DATA_EXPORT_VM_ZONES(ZONE) \
11370 ZONE(vm_zone, name, AST_DATA_STRING) \
11371 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11372 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11373
11374 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11375
11376
11377
11378
11379
11380
11381
11382
11383 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11384 struct ast_data *data_root, struct ast_vm_user *user)
11385 {
11386 struct ast_data *data_user, *data_zone;
11387 struct ast_data *data_state;
11388 struct vm_zone *zone = NULL;
11389 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11390 char ext_context[256] = "";
11391
11392 data_user = ast_data_add_node(data_root, "user");
11393 if (!data_user) {
11394 return -1;
11395 }
11396
11397 ast_data_add_structure(ast_vm_user, data_user, user);
11398
11399 AST_LIST_LOCK(&zones);
11400 AST_LIST_TRAVERSE(&zones, zone, list) {
11401 if (!strcmp(zone->name, user->zonetag)) {
11402 break;
11403 }
11404 }
11405 AST_LIST_UNLOCK(&zones);
11406
11407
11408 data_state = ast_data_add_node(data_user, "state");
11409 if (!data_state) {
11410 return -1;
11411 }
11412 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11413 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11414 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11415 ast_data_add_int(data_state, "newmsg", newmsg);
11416 ast_data_add_int(data_state, "oldmsg", oldmsg);
11417
11418 if (zone) {
11419 data_zone = ast_data_add_node(data_user, "zone");
11420 ast_data_add_structure(vm_zone, data_zone, zone);
11421 }
11422
11423 if (!ast_data_search_match(search, data_user)) {
11424 ast_data_remove_node(data_root, data_user);
11425 }
11426
11427 return 0;
11428 }
11429
11430 static int vm_users_data_provider_get(const struct ast_data_search *search,
11431 struct ast_data *data_root)
11432 {
11433 struct ast_vm_user *user;
11434
11435 AST_LIST_LOCK(&users);
11436 AST_LIST_TRAVERSE(&users, user, list) {
11437 vm_users_data_provider_get_helper(search, data_root, user);
11438 }
11439 AST_LIST_UNLOCK(&users);
11440
11441 return 0;
11442 }
11443
11444 static const struct ast_data_handler vm_users_data_provider = {
11445 .version = AST_DATA_HANDLER_VERSION,
11446 .get = vm_users_data_provider_get
11447 };
11448
11449 static const struct ast_data_entry vm_data_providers[] = {
11450 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11451 };
11452
11453 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11454 {
11455 int new = 0, old = 0, urgent = 0;
11456
11457 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11458
11459 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11460 mwi_sub->old_urgent = urgent;
11461 mwi_sub->old_new = new;
11462 mwi_sub->old_old = old;
11463 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11464 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11465 }
11466 }
11467
11468 static void poll_subscribed_mailboxes(void)
11469 {
11470 struct mwi_sub *mwi_sub;
11471
11472 AST_RWLIST_RDLOCK(&mwi_subs);
11473 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11474 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11475 poll_subscribed_mailbox(mwi_sub);
11476 }
11477 }
11478 AST_RWLIST_UNLOCK(&mwi_subs);
11479 }
11480
11481 static void *mb_poll_thread(void *data)
11482 {
11483 while (poll_thread_run) {
11484 struct timespec ts = { 0, };
11485 struct timeval wait;
11486
11487 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11488 ts.tv_sec = wait.tv_sec;
11489 ts.tv_nsec = wait.tv_usec * 1000;
11490
11491 ast_mutex_lock(&poll_lock);
11492 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11493 ast_mutex_unlock(&poll_lock);
11494
11495 if (!poll_thread_run)
11496 break;
11497
11498 poll_subscribed_mailboxes();
11499 }
11500
11501 return NULL;
11502 }
11503
11504 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11505 {
11506 ast_free(mwi_sub);
11507 }
11508
11509 static int handle_unsubscribe(void *datap)
11510 {
11511 struct mwi_sub *mwi_sub;
11512 uint32_t *uniqueid = datap;
11513
11514 AST_RWLIST_WRLOCK(&mwi_subs);
11515 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11516 if (mwi_sub->uniqueid == *uniqueid) {
11517 AST_LIST_REMOVE_CURRENT(entry);
11518 break;
11519 }
11520 }
11521 AST_RWLIST_TRAVERSE_SAFE_END
11522 AST_RWLIST_UNLOCK(&mwi_subs);
11523
11524 if (mwi_sub)
11525 mwi_sub_destroy(mwi_sub);
11526
11527 ast_free(uniqueid);
11528 return 0;
11529 }
11530
11531 static int handle_subscribe(void *datap)
11532 {
11533 unsigned int len;
11534 struct mwi_sub *mwi_sub;
11535 struct mwi_sub_task *p = datap;
11536
11537 len = sizeof(*mwi_sub);
11538 if (!ast_strlen_zero(p->mailbox))
11539 len += strlen(p->mailbox);
11540
11541 if (!ast_strlen_zero(p->context))
11542 len += strlen(p->context) + 1;
11543
11544 if (!(mwi_sub = ast_calloc(1, len)))
11545 return -1;
11546
11547 mwi_sub->uniqueid = p->uniqueid;
11548 if (!ast_strlen_zero(p->mailbox))
11549 strcpy(mwi_sub->mailbox, p->mailbox);
11550
11551 if (!ast_strlen_zero(p->context)) {
11552 strcat(mwi_sub->mailbox, "@");
11553 strcat(mwi_sub->mailbox, p->context);
11554 }
11555
11556 AST_RWLIST_WRLOCK(&mwi_subs);
11557 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11558 AST_RWLIST_UNLOCK(&mwi_subs);
11559 ast_free((void *) p->mailbox);
11560 ast_free((void *) p->context);
11561 ast_free(p);
11562 poll_subscribed_mailbox(mwi_sub);
11563 return 0;
11564 }
11565
11566 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11567 {
11568 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11569
11570 if (!uniqueid) {
11571 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11572 return;
11573 }
11574
11575 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11576 ast_free(uniqueid);
11577 return;
11578 }
11579
11580 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11581 ast_free(uniqueid);
11582 return;
11583 }
11584
11585 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11586 *uniqueid = u;
11587 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11588 ast_free(uniqueid);
11589 }
11590 }
11591
11592 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11593 {
11594 struct mwi_sub_task *mwist;
11595
11596 if (ast_event_get_type(event) != AST_EVENT_SUB)
11597 return;
11598
11599 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11600 return;
11601
11602 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11603 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11604 return;
11605 }
11606 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11607 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11608 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11609
11610 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11611 ast_free(mwist);
11612 }
11613 }
11614
11615 static void start_poll_thread(void)
11616 {
11617 int errcode;
11618 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11619 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11620 AST_EVENT_IE_END);
11621
11622 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11623 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11624 AST_EVENT_IE_END);
11625
11626 if (mwi_sub_sub)
11627 ast_event_report_subs(mwi_sub_sub);
11628
11629 poll_thread_run = 1;
11630
11631 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11632 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11633 }
11634 }
11635
11636 static void stop_poll_thread(void)
11637 {
11638 poll_thread_run = 0;
11639
11640 if (mwi_sub_sub) {
11641 ast_event_unsubscribe(mwi_sub_sub);
11642 mwi_sub_sub = NULL;
11643 }
11644
11645 if (mwi_unsub_sub) {
11646 ast_event_unsubscribe(mwi_unsub_sub);
11647 mwi_unsub_sub = NULL;
11648 }
11649
11650 ast_mutex_lock(&poll_lock);
11651 ast_cond_signal(&poll_cond);
11652 ast_mutex_unlock(&poll_lock);
11653
11654 pthread_join(poll_thread, NULL);
11655
11656 poll_thread = AST_PTHREADT_NULL;
11657 }
11658
11659
11660 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11661 {
11662 struct ast_vm_user *vmu = NULL;
11663 const char *id = astman_get_header(m, "ActionID");
11664 char actionid[128] = "";
11665
11666 if (!ast_strlen_zero(id))
11667 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11668
11669 AST_LIST_LOCK(&users);
11670
11671 if (AST_LIST_EMPTY(&users)) {
11672 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11673 AST_LIST_UNLOCK(&users);
11674 return RESULT_SUCCESS;
11675 }
11676
11677 astman_send_ack(s, m, "Voicemail user list will follow");
11678
11679 AST_LIST_TRAVERSE(&users, vmu, list) {
11680 char dirname[256];
11681
11682 #ifdef IMAP_STORAGE
11683 int new, old;
11684 inboxcount(vmu->mailbox, &new, &old);
11685 #endif
11686
11687 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11688 astman_append(s,
11689 "%s"
11690 "Event: VoicemailUserEntry\r\n"
11691 "VMContext: %s\r\n"
11692 "VoiceMailbox: %s\r\n"
11693 "Fullname: %s\r\n"
11694 "Email: %s\r\n"
11695 "Pager: %s\r\n"
11696 "ServerEmail: %s\r\n"
11697 "MailCommand: %s\r\n"
11698 "Language: %s\r\n"
11699 "TimeZone: %s\r\n"
11700 "Callback: %s\r\n"
11701 "Dialout: %s\r\n"
11702 "UniqueID: %s\r\n"
11703 "ExitContext: %s\r\n"
11704 "SayDurationMinimum: %d\r\n"
11705 "SayEnvelope: %s\r\n"
11706 "SayCID: %s\r\n"
11707 "AttachMessage: %s\r\n"
11708 "AttachmentFormat: %s\r\n"
11709 "DeleteMessage: %s\r\n"
11710 "VolumeGain: %.2f\r\n"
11711 "CanReview: %s\r\n"
11712 "CallOperator: %s\r\n"
11713 "MaxMessageCount: %d\r\n"
11714 "MaxMessageLength: %d\r\n"
11715 "NewMessageCount: %d\r\n"
11716 #ifdef IMAP_STORAGE
11717 "OldMessageCount: %d\r\n"
11718 "IMAPUser: %s\r\n"
11719 #endif
11720 "\r\n",
11721 actionid,
11722 vmu->context,
11723 vmu->mailbox,
11724 vmu->fullname,
11725 vmu->email,
11726 vmu->pager,
11727 vmu->serveremail,
11728 vmu->mailcmd,
11729 vmu->language,
11730 vmu->zonetag,
11731 vmu->callback,
11732 vmu->dialout,
11733 vmu->uniqueid,
11734 vmu->exit,
11735 vmu->saydurationm,
11736 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11737 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11738 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11739 vmu->attachfmt,
11740 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11741 vmu->volgain,
11742 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11743 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11744 vmu->maxmsg,
11745 vmu->maxsecs,
11746 #ifdef IMAP_STORAGE
11747 new, old, vmu->imapuser
11748 #else
11749 count_messages(vmu, dirname)
11750 #endif
11751 );
11752 }
11753 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11754
11755 AST_LIST_UNLOCK(&users);
11756
11757 return RESULT_SUCCESS;
11758 }
11759
11760
11761 static void free_vm_users(void)
11762 {
11763 struct ast_vm_user *current;
11764 AST_LIST_LOCK(&users);
11765 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11766 ast_set_flag(current, VM_ALLOCED);
11767 free_user(current);
11768 }
11769 AST_LIST_UNLOCK(&users);
11770 }
11771
11772
11773 static void free_vm_zones(void)
11774 {
11775 struct vm_zone *zcur;
11776 AST_LIST_LOCK(&zones);
11777 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11778 free_zone(zcur);
11779 AST_LIST_UNLOCK(&zones);
11780 }
11781
11782 static const char *substitute_escapes(const char *value)
11783 {
11784 char *current;
11785
11786
11787 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11788
11789 ast_str_reset(str);
11790
11791
11792 for (current = (char *) value; *current; current++) {
11793 if (*current == '\\') {
11794 current++;
11795 if (!*current) {
11796 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11797 break;
11798 }
11799 switch (*current) {
11800 case '\\':
11801 ast_str_append(&str, 0, "\\");
11802 break;
11803 case 'r':
11804 ast_str_append(&str, 0, "\r");
11805 break;
11806 case 'n':
11807 #ifdef IMAP_STORAGE
11808 if (!str->used || str->str[str->used - 1] != '\r') {
11809 ast_str_append(&str, 0, "\r");
11810 }
11811 #endif
11812 ast_str_append(&str, 0, "\n");
11813 break;
11814 case 't':
11815 ast_str_append(&str, 0, "\t");
11816 break;
11817 default:
11818 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11819 break;
11820 }
11821 } else {
11822 ast_str_append(&str, 0, "%c", *current);
11823 }
11824 }
11825
11826 return ast_str_buffer(str);
11827 }
11828
11829 static int load_config(int reload)
11830 {
11831 struct ast_config *cfg, *ucfg;
11832 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11833 int res;
11834
11835 ast_unload_realtime("voicemail");
11836 ast_unload_realtime("voicemail_data");
11837
11838 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11839 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11840 return 0;
11841 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11842 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11843 ucfg = NULL;
11844 }
11845 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11846 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11847 ast_config_destroy(ucfg);
11848 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11849 return 0;
11850 }
11851 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11852 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11853 return 0;
11854 } else {
11855 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11856 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11857 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11858 ucfg = NULL;
11859 }
11860 }
11861
11862 res = actual_load_config(reload, cfg, ucfg);
11863
11864 ast_config_destroy(cfg);
11865 ast_config_destroy(ucfg);
11866
11867 return res;
11868 }
11869
11870 #ifdef TEST_FRAMEWORK
11871 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11872 {
11873 ast_unload_realtime("voicemail");
11874 ast_unload_realtime("voicemail_data");
11875 return actual_load_config(reload, cfg, ucfg);
11876 }
11877 #endif
11878
11879 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11880 {
11881 struct ast_vm_user *current;
11882 char *cat;
11883 struct ast_variable *var;
11884 const char *val;
11885 char *q, *stringp, *tmp;
11886 int x;
11887 int tmpadsi[4];
11888 char secretfn[PATH_MAX] = "";
11889
11890 #ifdef IMAP_STORAGE
11891 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11892 #endif
11893
11894 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11895 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11896 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11897 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11898 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11899
11900
11901 free_vm_users();
11902
11903
11904 free_vm_zones();
11905
11906 AST_LIST_LOCK(&users);
11907
11908 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11909 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11910
11911 if (cfg) {
11912
11913
11914 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11915 val = "default";
11916 ast_copy_string(userscontext, val, sizeof(userscontext));
11917
11918 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11919 val = "yes";
11920 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11921
11922 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11923 val = "no";
11924 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11925
11926 volgain = 0.0;
11927 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11928 sscanf(val, "%30lf", &volgain);
11929
11930 #ifdef ODBC_STORAGE
11931 strcpy(odbc_database, "asterisk");
11932 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11933 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11934 }
11935 strcpy(odbc_table, "voicemessages");
11936 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11937 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11938 }
11939 #endif
11940
11941 strcpy(mailcmd, SENDMAIL);
11942 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11943 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11944
11945 maxsilence = 0;
11946 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11947 maxsilence = atoi(val);
11948 if (maxsilence > 0)
11949 maxsilence *= 1000;
11950 }
11951
11952 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11953 maxmsg = MAXMSG;
11954 } else {
11955 maxmsg = atoi(val);
11956 if (maxmsg < 0) {
11957 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11958 maxmsg = MAXMSG;
11959 } else if (maxmsg > MAXMSGLIMIT) {
11960 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11961 maxmsg = MAXMSGLIMIT;
11962 }
11963 }
11964
11965 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11966 maxdeletedmsg = 0;
11967 } else {
11968 if (sscanf(val, "%30d", &x) == 1)
11969 maxdeletedmsg = x;
11970 else if (ast_true(val))
11971 maxdeletedmsg = MAXMSG;
11972 else
11973 maxdeletedmsg = 0;
11974
11975 if (maxdeletedmsg < 0) {
11976 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11977 maxdeletedmsg = MAXMSG;
11978 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11979 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11980 maxdeletedmsg = MAXMSGLIMIT;
11981 }
11982 }
11983
11984
11985 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11986 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11987 }
11988
11989
11990 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11991 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11992 }
11993
11994
11995 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11996 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11997 pwdchange = PWDCHANGE_EXTERNAL;
11998 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11999 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12000 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
12001 }
12002
12003
12004 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
12005 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
12006 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
12007 }
12008
12009 #ifdef IMAP_STORAGE
12010
12011 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
12012 ast_copy_string(imapserver, val, sizeof(imapserver));
12013 } else {
12014 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
12015 }
12016
12017 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
12018 ast_copy_string(imapport, val, sizeof(imapport));
12019 } else {
12020 ast_copy_string(imapport, "143", sizeof(imapport));
12021 }
12022
12023 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
12024 ast_copy_string(imapflags, val, sizeof(imapflags));
12025 }
12026
12027 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12028 ast_copy_string(authuser, val, sizeof(authuser));
12029 }
12030
12031 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12032 ast_copy_string(authpassword, val, sizeof(authpassword));
12033 }
12034
12035 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12036 if (ast_false(val))
12037 expungeonhangup = 0;
12038 else
12039 expungeonhangup = 1;
12040 } else {
12041 expungeonhangup = 1;
12042 }
12043
12044 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12045 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12046 } else {
12047 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12048 }
12049 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12050 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12051 }
12052 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12053 imapgreetings = ast_true(val);
12054 } else {
12055 imapgreetings = 0;
12056 }
12057 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12058 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12059 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12060
12061 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12062 } else {
12063 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12064 }
12065
12066
12067
12068
12069
12070 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12071 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12072 } else {
12073 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12074 }
12075
12076 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12077 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12078 } else {
12079 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12080 }
12081
12082 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12083 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12084 } else {
12085 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12086 }
12087
12088 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12089 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12090 } else {
12091 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12092 }
12093
12094
12095 imapversion++;
12096 #endif
12097
12098 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12099 ast_copy_string(externnotify, val, sizeof(externnotify));
12100 ast_debug(1, "found externnotify: %s\n", externnotify);
12101 } else {
12102 externnotify[0] = '\0';
12103 }
12104
12105
12106 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12107 ast_debug(1, "Enabled SMDI voicemail notification\n");
12108 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12109 smdi_iface = ast_smdi_interface_find(val);
12110 } else {
12111 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12112 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12113 }
12114 if (!smdi_iface) {
12115 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12116 }
12117 }
12118
12119
12120 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12121 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12122 silencethreshold = atoi(val);
12123
12124 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12125 val = ASTERISK_USERNAME;
12126 ast_copy_string(serveremail, val, sizeof(serveremail));
12127
12128 vmmaxsecs = 0;
12129 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12130 if (sscanf(val, "%30d", &x) == 1) {
12131 vmmaxsecs = x;
12132 } else {
12133 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12134 }
12135 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12136 static int maxmessage_deprecate = 0;
12137 if (maxmessage_deprecate == 0) {
12138 maxmessage_deprecate = 1;
12139 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12140 }
12141 if (sscanf(val, "%30d", &x) == 1) {
12142 vmmaxsecs = x;
12143 } else {
12144 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12145 }
12146 }
12147
12148 vmminsecs = 0;
12149 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12150 if (sscanf(val, "%30d", &x) == 1) {
12151 vmminsecs = x;
12152 if (maxsilence / 1000 >= vmminsecs) {
12153 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12154 }
12155 } else {
12156 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12157 }
12158 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12159 static int maxmessage_deprecate = 0;
12160 if (maxmessage_deprecate == 0) {
12161 maxmessage_deprecate = 1;
12162 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12163 }
12164 if (sscanf(val, "%30d", &x) == 1) {
12165 vmminsecs = x;
12166 if (maxsilence / 1000 >= vmminsecs) {
12167 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12168 }
12169 } else {
12170 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12171 }
12172 }
12173
12174 val = ast_variable_retrieve(cfg, "general", "format");
12175 if (!val) {
12176 val = "wav";
12177 } else {
12178 tmp = ast_strdupa(val);
12179 val = ast_format_str_reduce(tmp);
12180 if (!val) {
12181 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12182 val = "wav";
12183 }
12184 }
12185 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12186
12187 skipms = 3000;
12188 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12189 if (sscanf(val, "%30d", &x) == 1) {
12190 maxgreet = x;
12191 } else {
12192 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12193 }
12194 }
12195
12196 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12197 if (sscanf(val, "%30d", &x) == 1) {
12198 skipms = x;
12199 } else {
12200 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12201 }
12202 }
12203
12204 maxlogins = 3;
12205 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12206 if (sscanf(val, "%30d", &x) == 1) {
12207 maxlogins = x;
12208 } else {
12209 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12210 }
12211 }
12212
12213 minpassword = MINPASSWORD;
12214 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12215 if (sscanf(val, "%30d", &x) == 1) {
12216 minpassword = x;
12217 } else {
12218 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12219 }
12220 }
12221
12222
12223 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12224 val = "no";
12225 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12226
12227
12228 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12229 val = "no";
12230 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12231
12232 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12233 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12234 stringp = ast_strdupa(val);
12235 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12236 if (!ast_strlen_zero(stringp)) {
12237 q = strsep(&stringp, ",");
12238 while ((*q == ' ')||(*q == '\t'))
12239 q++;
12240 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12241 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12242 } else {
12243 cidinternalcontexts[x][0] = '\0';
12244 }
12245 }
12246 }
12247 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12248 ast_debug(1, "VM Review Option disabled globally\n");
12249 val = "no";
12250 }
12251 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12252
12253
12254 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12255 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12256 val = "no";
12257 } else {
12258 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12259 }
12260 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12261 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12262 ast_debug(1, "VM next message wrap disabled globally\n");
12263 val = "no";
12264 }
12265 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12266
12267 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12268 ast_debug(1, "VM Operator break disabled globally\n");
12269 val = "no";
12270 }
12271 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12272
12273 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12274 ast_debug(1, "VM CID Info before msg disabled globally\n");
12275 val = "no";
12276 }
12277 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12278
12279 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12280 ast_debug(1, "Send Voicemail msg disabled globally\n");
12281 val = "no";
12282 }
12283 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12284
12285 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12286 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12287 val = "yes";
12288 }
12289 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12290
12291 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12292 ast_debug(1, "Move Heard enabled globally\n");
12293 val = "yes";
12294 }
12295 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12296
12297 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12298 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12299 val = "no";
12300 }
12301 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12302
12303 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12304 ast_debug(1, "Duration info before msg enabled globally\n");
12305 val = "yes";
12306 }
12307 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12308
12309 saydurationminfo = 2;
12310 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12311 if (sscanf(val, "%30d", &x) == 1) {
12312 saydurationminfo = x;
12313 } else {
12314 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12315 }
12316 }
12317
12318 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12319 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12320 val = "no";
12321 }
12322 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12323
12324 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12325 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12326 ast_debug(1, "found dialout context: %s\n", dialcontext);
12327 } else {
12328 dialcontext[0] = '\0';
12329 }
12330
12331 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12332 ast_copy_string(callcontext, val, sizeof(callcontext));
12333 ast_debug(1, "found callback context: %s\n", callcontext);
12334 } else {
12335 callcontext[0] = '\0';
12336 }
12337
12338 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12339 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12340 ast_debug(1, "found operator context: %s\n", exitcontext);
12341 } else {
12342 exitcontext[0] = '\0';
12343 }
12344
12345
12346 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12347 ast_copy_string(vm_password, val, sizeof(vm_password));
12348 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12349 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12350 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12351 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12352 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12353 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12354 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12355 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12356 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12357 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12358 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12359 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12360 }
12361 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12362 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12363 }
12364
12365 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12366 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12367 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12368 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12369 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12370 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12371 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12372 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12373 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12374 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12375
12376 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12377 val = "no";
12378 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12379
12380 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12381 val = "voicemail.conf";
12382 }
12383 if (!(strcmp(val, "spooldir"))) {
12384 passwordlocation = OPT_PWLOC_SPOOLDIR;
12385 } else {
12386 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12387 }
12388
12389 poll_freq = DEFAULT_POLL_FREQ;
12390 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12391 if (sscanf(val, "%30u", &poll_freq) != 1) {
12392 poll_freq = DEFAULT_POLL_FREQ;
12393 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12394 }
12395 }
12396
12397 poll_mailboxes = 0;
12398 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12399 poll_mailboxes = ast_true(val);
12400
12401 memset(fromstring, 0, sizeof(fromstring));
12402 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12403 strcpy(charset, "ISO-8859-1");
12404 if (emailbody) {
12405 ast_free(emailbody);
12406 emailbody = NULL;
12407 }
12408 if (emailsubject) {
12409 ast_free(emailsubject);
12410 emailsubject = NULL;
12411 }
12412 if (pagerbody) {
12413 ast_free(pagerbody);
12414 pagerbody = NULL;
12415 }
12416 if (pagersubject) {
12417 ast_free(pagersubject);
12418 pagersubject = NULL;
12419 }
12420 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12421 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12422 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12423 ast_copy_string(fromstring, val, sizeof(fromstring));
12424 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12425 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12426 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12427 ast_copy_string(charset, val, sizeof(charset));
12428 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12429 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12430 for (x = 0; x < 4; x++) {
12431 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12432 }
12433 }
12434 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12435 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12436 for (x = 0; x < 4; x++) {
12437 memcpy(&adsisec[x], &tmpadsi[x], 1);
12438 }
12439 }
12440 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12441 if (atoi(val)) {
12442 adsiver = atoi(val);
12443 }
12444 }
12445 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12446 ast_copy_string(zonetag, val, sizeof(zonetag));
12447 }
12448 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12449 ast_copy_string(locale, val, sizeof(locale));
12450 }
12451 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12452 emailsubject = ast_strdup(substitute_escapes(val));
12453 }
12454 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12455 emailbody = ast_strdup(substitute_escapes(val));
12456 }
12457 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12458 pagersubject = ast_strdup(substitute_escapes(val));
12459 }
12460 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12461 pagerbody = ast_strdup(substitute_escapes(val));
12462 }
12463
12464
12465 if (ucfg) {
12466 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12467 if (!strcasecmp(cat, "general")) {
12468 continue;
12469 }
12470 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12471 continue;
12472 if ((current = find_or_create(userscontext, cat))) {
12473 populate_defaults(current);
12474 apply_options_full(current, ast_variable_browse(ucfg, cat));
12475 ast_copy_string(current->context, userscontext, sizeof(current->context));
12476 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12477 current->passwordlocation = OPT_PWLOC_USERSCONF;
12478 }
12479
12480 switch (current->passwordlocation) {
12481 case OPT_PWLOC_SPOOLDIR:
12482 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12483 read_password_from_file(secretfn, current->password, sizeof(current->password));
12484 }
12485 }
12486 }
12487 }
12488
12489
12490 cat = ast_category_browse(cfg, NULL);
12491 while (cat) {
12492 if (strcasecmp(cat, "general")) {
12493 var = ast_variable_browse(cfg, cat);
12494 if (strcasecmp(cat, "zonemessages")) {
12495
12496 while (var) {
12497 append_mailbox(cat, var->name, var->value);
12498 var = var->next;
12499 }
12500 } else {
12501
12502 while (var) {
12503 struct vm_zone *z;
12504 if ((z = ast_malloc(sizeof(*z)))) {
12505 char *msg_format, *tzone;
12506 msg_format = ast_strdupa(var->value);
12507 tzone = strsep(&msg_format, "|,");
12508 if (msg_format) {
12509 ast_copy_string(z->name, var->name, sizeof(z->name));
12510 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12511 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12512 AST_LIST_LOCK(&zones);
12513 AST_LIST_INSERT_HEAD(&zones, z, list);
12514 AST_LIST_UNLOCK(&zones);
12515 } else {
12516 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12517 ast_free(z);
12518 }
12519 } else {
12520 AST_LIST_UNLOCK(&users);
12521 return -1;
12522 }
12523 var = var->next;
12524 }
12525 }
12526 }
12527 cat = ast_category_browse(cfg, cat);
12528 }
12529
12530 AST_LIST_UNLOCK(&users);
12531
12532 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12533 start_poll_thread();
12534 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12535 stop_poll_thread();;
12536
12537 return 0;
12538 } else {
12539 AST_LIST_UNLOCK(&users);
12540 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12541 return 0;
12542 }
12543 }
12544
12545 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12546 {
12547 int res = -1;
12548 char dir[PATH_MAX];
12549 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12550 ast_debug(2, "About to try retrieving name file %s\n", dir);
12551 RETRIEVE(dir, -1, mailbox, context);
12552 if (ast_fileexists(dir, NULL, NULL)) {
12553 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12554 }
12555 DISPOSE(dir, -1);
12556 return res;
12557 }
12558
12559 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12560 struct ast_config *pwconf;
12561 struct ast_flags config_flags = { 0 };
12562
12563 pwconf = ast_config_load(secretfn, config_flags);
12564 if (pwconf) {
12565 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12566 if (val) {
12567 ast_copy_string(password, val, passwordlen);
12568 ast_config_destroy(pwconf);
12569 return;
12570 }
12571 ast_config_destroy(pwconf);
12572 }
12573 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12574 }
12575
12576 static int write_password_to_file(const char *secretfn, const char *password) {
12577 struct ast_config *conf;
12578 struct ast_category *cat;
12579 struct ast_variable *var;
12580 int res = -1;
12581
12582 if (!(conf = ast_config_new())) {
12583 ast_log(LOG_ERROR, "Error creating new config structure\n");
12584 return res;
12585 }
12586 if (!(cat = ast_category_new("general", "", 1))) {
12587 ast_log(LOG_ERROR, "Error creating new category structure\n");
12588 ast_config_destroy(conf);
12589 return res;
12590 }
12591 if (!(var = ast_variable_new("password", password, ""))) {
12592 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12593 ast_config_destroy(conf);
12594 ast_category_destroy(cat);
12595 return res;
12596 }
12597 ast_category_append(conf, cat);
12598 ast_variable_append(cat, var);
12599 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12600 res = 0;
12601 } else {
12602 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12603 }
12604
12605 ast_config_destroy(conf);
12606 return res;
12607 }
12608
12609 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12610 {
12611 char *context;
12612 char *args_copy;
12613 int res;
12614
12615 if (ast_strlen_zero(data)) {
12616 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12617 return -1;
12618 }
12619
12620 args_copy = ast_strdupa(data);
12621 if ((context = strchr(args_copy, '@'))) {
12622 *context++ = '\0';
12623 } else {
12624 context = "default";
12625 }
12626
12627 if ((res = sayname(chan, args_copy, context) < 0)) {
12628 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12629 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12630 if (!res) {
12631 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12632 }
12633 }
12634
12635 return res;
12636 }
12637
12638 #ifdef TEST_FRAMEWORK
12639 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12640 {
12641 return 0;
12642 }
12643
12644 static struct ast_frame *fake_read(struct ast_channel *ast)
12645 {
12646 return &ast_null_frame;
12647 }
12648
12649 AST_TEST_DEFINE(test_voicemail_vmsayname)
12650 {
12651 char dir[PATH_MAX];
12652 char dir2[PATH_MAX];
12653 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12654 static const char TEST_EXTENSION[] = "1234";
12655
12656 struct ast_channel *test_channel1 = NULL;
12657 int res = -1;
12658
12659 static const struct ast_channel_tech fake_tech = {
12660 .write = fake_write,
12661 .read = fake_read,
12662 };
12663
12664 switch (cmd) {
12665 case TEST_INIT:
12666 info->name = "vmsayname_exec";
12667 info->category = "/apps/app_voicemail/";
12668 info->summary = "Vmsayname unit test";
12669 info->description =
12670 "This tests passing various parameters to vmsayname";
12671 return AST_TEST_NOT_RUN;
12672 case TEST_EXECUTE:
12673 break;
12674 }
12675
12676 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12677 NULL, NULL, 0, 0, "TestChannel1"))) {
12678 goto exit_vmsayname_test;
12679 }
12680
12681
12682 test_channel1->nativeformats = AST_FORMAT_GSM;
12683 test_channel1->writeformat = AST_FORMAT_GSM;
12684 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12685 test_channel1->readformat = AST_FORMAT_GSM;
12686 test_channel1->rawreadformat = AST_FORMAT_GSM;
12687 test_channel1->tech = &fake_tech;
12688
12689 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12690 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12691 if (!(res = vmsayname_exec(test_channel1, dir))) {
12692 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12693 if (ast_fileexists(dir, NULL, NULL)) {
12694 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12695 res = -1;
12696 goto exit_vmsayname_test;
12697 } else {
12698
12699 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12700 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12701 goto exit_vmsayname_test;
12702 }
12703 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12704 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12705
12706 if ((res = symlink(dir, dir2))) {
12707 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12708 goto exit_vmsayname_test;
12709 }
12710 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12711 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12712 res = vmsayname_exec(test_channel1, dir);
12713
12714
12715 unlink(dir2);
12716 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12717 rmdir(dir2);
12718 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12719 rmdir(dir2);
12720 }
12721 }
12722
12723 exit_vmsayname_test:
12724
12725 if (test_channel1) {
12726 ast_hangup(test_channel1);
12727 }
12728
12729 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12730 }
12731
12732 AST_TEST_DEFINE(test_voicemail_msgcount)
12733 {
12734 int i, j, res = AST_TEST_PASS, syserr;
12735 struct ast_vm_user *vmu;
12736 struct vm_state vms;
12737 #ifdef IMAP_STORAGE
12738 struct ast_channel *chan = NULL;
12739 #endif
12740 struct {
12741 char dir[256];
12742 char file[256];
12743 char txtfile[256];
12744 } tmp[3];
12745 char syscmd[256];
12746 const char origweasels[] = "tt-weasels";
12747 const char testcontext[] = "test";
12748 const char testmailbox[] = "00000000";
12749 const char testspec[] = "00000000@test";
12750 FILE *txt;
12751 int new, old, urgent;
12752 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12753 const int folder2mbox[3] = { 1, 11, 0 };
12754 const int expected_results[3][12] = {
12755
12756 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12757 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12758 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12759 };
12760
12761 switch (cmd) {
12762 case TEST_INIT:
12763 info->name = "test_voicemail_msgcount";
12764 info->category = "/apps/app_voicemail/";
12765 info->summary = "Test Voicemail status checks";
12766 info->description =
12767 "Verify that message counts are correct when retrieved through the public API";
12768 return AST_TEST_NOT_RUN;
12769 case TEST_EXECUTE:
12770 break;
12771 }
12772
12773
12774 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12775 if ((syserr = ast_safe_system(syscmd))) {
12776 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12777 syserr > 0 ? strerror(syserr) : "unable to fork()");
12778 return AST_TEST_FAIL;
12779 }
12780
12781 #ifdef IMAP_STORAGE
12782 if (!(chan = ast_dummy_channel_alloc())) {
12783 ast_test_status_update(test, "Unable to create dummy channel\n");
12784 return AST_TEST_FAIL;
12785 }
12786 #endif
12787
12788 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12789 !(vmu = find_or_create(testcontext, testmailbox))) {
12790 ast_test_status_update(test, "Cannot create vmu structure\n");
12791 ast_unreplace_sigchld();
12792 #ifdef IMAP_STORAGE
12793 chan = ast_channel_unref(chan);
12794 #endif
12795 return AST_TEST_FAIL;
12796 }
12797
12798 populate_defaults(vmu);
12799 memset(&vms, 0, sizeof(vms));
12800
12801
12802 for (i = 0; i < 3; i++) {
12803 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12804 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12805 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12806
12807 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12808 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12809 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12810 if ((syserr = ast_safe_system(syscmd))) {
12811 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12812 syserr > 0 ? strerror(syserr) : "unable to fork()");
12813 ast_unreplace_sigchld();
12814 #ifdef IMAP_STORAGE
12815 chan = ast_channel_unref(chan);
12816 #endif
12817 return AST_TEST_FAIL;
12818 }
12819 }
12820
12821 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12822 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12823 fclose(txt);
12824 } else {
12825 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12826 res = AST_TEST_FAIL;
12827 break;
12828 }
12829 open_mailbox(&vms, vmu, folder2mbox[i]);
12830 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12831
12832
12833 for (j = 0; j < 3; j++) {
12834
12835 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12836 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12837 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12838 res = AST_TEST_FAIL;
12839 }
12840 }
12841
12842 new = old = urgent = 0;
12843 if (ast_app_inboxcount(testspec, &new, &old)) {
12844 ast_test_status_update(test, "inboxcount returned failure\n");
12845 res = AST_TEST_FAIL;
12846 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12847 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12848 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12849 res = AST_TEST_FAIL;
12850 }
12851
12852 new = old = urgent = 0;
12853 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12854 ast_test_status_update(test, "inboxcount2 returned failure\n");
12855 res = AST_TEST_FAIL;
12856 } else if (old != expected_results[i][6 + 0] ||
12857 urgent != expected_results[i][6 + 1] ||
12858 new != expected_results[i][6 + 2] ) {
12859 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12860 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12861 res = AST_TEST_FAIL;
12862 }
12863
12864 new = old = urgent = 0;
12865 for (j = 0; j < 3; j++) {
12866 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12867 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12868 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12869 res = AST_TEST_FAIL;
12870 }
12871 }
12872 }
12873
12874 for (i = 0; i < 3; i++) {
12875
12876
12877
12878 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12879 DISPOSE(tmp[i].dir, 0);
12880 }
12881
12882 if (vms.deleted) {
12883 ast_free(vms.deleted);
12884 }
12885 if (vms.heard) {
12886 ast_free(vms.heard);
12887 }
12888
12889 #ifdef IMAP_STORAGE
12890 chan = ast_channel_unref(chan);
12891 #endif
12892
12893
12894 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12895 if ((syserr = ast_safe_system(syscmd))) {
12896 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12897 syserr > 0 ? strerror(syserr) : "unable to fork()");
12898 }
12899
12900 return res;
12901 }
12902
12903 AST_TEST_DEFINE(test_voicemail_notify_endl)
12904 {
12905 int res = AST_TEST_PASS;
12906 char testcontext[] = "test";
12907 char testmailbox[] = "00000000";
12908 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12909 char attach[256], attach2[256];
12910 char buf[256] = "";
12911 struct ast_channel *chan = NULL;
12912 struct ast_vm_user *vmu, vmus = {
12913 .flags = 0,
12914 };
12915 FILE *file;
12916 struct {
12917 char *name;
12918 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12919 void *location;
12920 union {
12921 int intval;
12922 char *strval;
12923 } u;
12924 } test_items[] = {
12925 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12926 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12927 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12928 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12929 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12930 { "attach2", STRPTR, attach2, .u.strval = "" },
12931 { "attach", STRPTR, attach, .u.strval = "" },
12932 };
12933 int which;
12934
12935 switch (cmd) {
12936 case TEST_INIT:
12937 info->name = "test_voicemail_notify_endl";
12938 info->category = "/apps/app_voicemail/";
12939 info->summary = "Test Voicemail notification end-of-line";
12940 info->description =
12941 "Verify that notification emails use a consistent end-of-line character";
12942 return AST_TEST_NOT_RUN;
12943 case TEST_EXECUTE:
12944 break;
12945 }
12946
12947 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12948 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12949
12950 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12951 !(vmu = find_or_create(testcontext, testmailbox))) {
12952 ast_test_status_update(test, "Cannot create vmu structure\n");
12953 return AST_TEST_NOT_RUN;
12954 }
12955
12956 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12957 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12958 return AST_TEST_NOT_RUN;
12959 }
12960
12961 populate_defaults(vmu);
12962 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12963 #ifdef IMAP_STORAGE
12964
12965 #endif
12966
12967 file = tmpfile();
12968 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12969
12970 rewind(file);
12971 if (ftruncate(fileno(file), 0)) {
12972 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12973 res = AST_TEST_FAIL;
12974 break;
12975 }
12976
12977
12978 if (test_items[which].type == INT) {
12979 *((int *) test_items[which].location) = test_items[which].u.intval;
12980 } else if (test_items[which].type == FLAGVAL) {
12981 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12982 ast_clear_flag(vmu, test_items[which].u.intval);
12983 } else {
12984 ast_set_flag(vmu, test_items[which].u.intval);
12985 }
12986 } else if (test_items[which].type == STATIC) {
12987 strcpy(test_items[which].location, test_items[which].u.strval);
12988 } else if (test_items[which].type == STRPTR) {
12989 test_items[which].location = test_items[which].u.strval;
12990 }
12991
12992 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12993 rewind(file);
12994 while (fgets(buf, sizeof(buf), file)) {
12995 if (
12996 #ifdef IMAP_STORAGE
12997 buf[strlen(buf) - 2] != '\r'
12998 #else
12999 buf[strlen(buf) - 2] == '\r'
13000 #endif
13001 || buf[strlen(buf) - 1] != '\n') {
13002 res = AST_TEST_FAIL;
13003 }
13004 }
13005 }
13006 fclose(file);
13007 return res;
13008 }
13009
13010 AST_TEST_DEFINE(test_voicemail_load_config)
13011 {
13012 int res = AST_TEST_PASS;
13013 struct ast_vm_user *vmu;
13014 struct ast_config *cfg;
13015 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
13016 int fd;
13017 FILE *file;
13018 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
13019
13020 switch (cmd) {
13021 case TEST_INIT:
13022 info->name = "test_voicemail_load_config";
13023 info->category = "/apps/app_voicemail/";
13024 info->summary = "Test loading Voicemail config";
13025 info->description =
13026 "Verify that configuration is loaded consistently. "
13027 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13028 "some options were loaded after the mailboxes were instantiated, causing "
13029 "those options not to be set correctly.";
13030 return AST_TEST_NOT_RUN;
13031 case TEST_EXECUTE:
13032 break;
13033 }
13034
13035
13036 if ((fd = mkstemp(config_filename)) < 0) {
13037 return AST_TEST_FAIL;
13038 }
13039 if (!(file = fdopen(fd, "w"))) {
13040 close(fd);
13041 unlink(config_filename);
13042 return AST_TEST_FAIL;
13043 }
13044 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13045 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13046 fputs("00000002 => 9999,Mrs. Test\n", file);
13047 fclose(file);
13048
13049 if (!(cfg = ast_config_load(config_filename, config_flags))) {
13050 res = AST_TEST_FAIL;
13051 goto cleanup;
13052 }
13053
13054 load_config_from_memory(1, cfg, NULL);
13055 ast_config_destroy(cfg);
13056
13057 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13058 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13059 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13060
13061 AST_LIST_LOCK(&users);
13062 AST_LIST_TRAVERSE(&users, vmu, list) {
13063 if (!strcmp(vmu->mailbox, "00000001")) {
13064 if (0);
13065 CHECK(vmu, callback, "othercontext")
13066 CHECK(vmu, locale, "nl_NL.UTF-8")
13067 CHECK(vmu, zonetag, "central")
13068 } else if (!strcmp(vmu->mailbox, "00000002")) {
13069 if (0);
13070 CHECK(vmu, callback, "somecontext")
13071 CHECK(vmu, locale, "de_DE.UTF-8")
13072 CHECK(vmu, zonetag, "european")
13073 }
13074 }
13075 AST_LIST_UNLOCK(&users);
13076
13077 #undef CHECK
13078
13079
13080 load_config(1);
13081
13082 cleanup:
13083 unlink(config_filename);
13084 return res;
13085 }
13086
13087 #endif
13088
13089 static int reload(void)
13090 {
13091 return load_config(1);
13092 }
13093
13094 static int unload_module(void)
13095 {
13096 int res;
13097
13098 res = ast_unregister_application(app);
13099 res |= ast_unregister_application(app2);
13100 res |= ast_unregister_application(app3);
13101 res |= ast_unregister_application(app4);
13102 res |= ast_unregister_application(sayname_app);
13103 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13104 res |= ast_manager_unregister("VoicemailUsersList");
13105 res |= ast_data_unregister(NULL);
13106 #ifdef TEST_FRAMEWORK
13107 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13108 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13109 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13110 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13111 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13112 #endif
13113 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13114 ast_uninstall_vm_functions();
13115 ao2_ref(inprocess_container, -1);
13116
13117 if (poll_thread != AST_PTHREADT_NULL)
13118 stop_poll_thread();
13119
13120 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13121 ast_unload_realtime("voicemail");
13122 ast_unload_realtime("voicemail_data");
13123
13124 free_vm_users();
13125 free_vm_zones();
13126 return res;
13127 }
13128
13129 static int load_module(void)
13130 {
13131 int res;
13132 my_umask = umask(0);
13133 umask(my_umask);
13134
13135 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13136 return AST_MODULE_LOAD_DECLINE;
13137 }
13138
13139
13140 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13141
13142 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13143 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13144 }
13145
13146 if ((res = load_config(0)))
13147 return res;
13148
13149 res = ast_register_application_xml(app, vm_exec);
13150 res |= ast_register_application_xml(app2, vm_execmain);
13151 res |= ast_register_application_xml(app3, vm_box_exists);
13152 res |= ast_register_application_xml(app4, vmauthenticate);
13153 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13154 res |= ast_custom_function_register(&mailbox_exists_acf);
13155 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13156 #ifdef TEST_FRAMEWORK
13157 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13158 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13159 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13160 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13161 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13162 #endif
13163
13164 if (res)
13165 return res;
13166
13167 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13168 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13169
13170 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13171 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13172 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13173
13174 return res;
13175 }
13176
13177 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13178 {
13179 int cmd = 0;
13180 char destination[80] = "";
13181 int retries = 0;
13182
13183 if (!num) {
13184 ast_verb(3, "Destination number will be entered manually\n");
13185 while (retries < 3 && cmd != 't') {
13186 destination[1] = '\0';
13187 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13188 if (!cmd)
13189 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13190 if (!cmd)
13191 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13192 if (!cmd) {
13193 cmd = ast_waitfordigit(chan, 6000);
13194 if (cmd)
13195 destination[0] = cmd;
13196 }
13197 if (!cmd) {
13198 retries++;
13199 } else {
13200
13201 if (cmd < 0)
13202 return 0;
13203 if (cmd == '*') {
13204 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13205 return 0;
13206 }
13207 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13208 retries++;
13209 else
13210 cmd = 't';
13211 }
13212 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13213 }
13214 if (retries >= 3) {
13215 return 0;
13216 }
13217
13218 } else {
13219 if (option_verbose > 2)
13220 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13221 ast_copy_string(destination, num, sizeof(destination));
13222 }
13223
13224 if (!ast_strlen_zero(destination)) {
13225 if (destination[strlen(destination) -1 ] == '*')
13226 return 0;
13227 if (option_verbose > 2)
13228 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13229 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13230 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13231 chan->priority = 0;
13232 return 9;
13233 }
13234 return 0;
13235 }
13236
13237
13238
13239
13240
13241
13242
13243
13244
13245
13246
13247
13248
13249
13250 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)
13251 {
13252 int res = 0;
13253 char filename[PATH_MAX];
13254 struct ast_config *msg_cfg = NULL;
13255 const char *origtime, *context;
13256 char *name, *num;
13257 int retries = 0;
13258 char *cid;
13259 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13260
13261 vms->starting = 0;
13262
13263 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13264
13265
13266 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13267 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13268 msg_cfg = ast_config_load(filename, config_flags);
13269 DISPOSE(vms->curdir, vms->curmsg);
13270 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13271 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13272 return 0;
13273 }
13274
13275 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13276 ast_config_destroy(msg_cfg);
13277 return 0;
13278 }
13279
13280 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13281
13282 context = ast_variable_retrieve(msg_cfg, "message", "context");
13283 if (!strncasecmp("macro", context, 5))
13284 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13285 switch (option) {
13286 case 3:
13287 if (!res)
13288 res = play_message_datetime(chan, vmu, origtime, filename);
13289 if (!res)
13290 res = play_message_callerid(chan, vms, cid, context, 0);
13291
13292 res = 't';
13293 break;
13294
13295 case 2:
13296
13297 if (ast_strlen_zero(cid))
13298 break;
13299
13300 ast_callerid_parse(cid, &name, &num);
13301 while ((res > -1) && (res != 't')) {
13302 switch (res) {
13303 case '1':
13304 if (num) {
13305
13306 res = dialout(chan, vmu, num, vmu->callback);
13307 if (res) {
13308 ast_config_destroy(msg_cfg);
13309 return 9;
13310 }
13311 } else {
13312 res = '2';
13313 }
13314 break;
13315
13316 case '2':
13317
13318 if (!ast_strlen_zero(vmu->dialout)) {
13319 res = dialout(chan, vmu, NULL, vmu->dialout);
13320 if (res) {
13321 ast_config_destroy(msg_cfg);
13322 return 9;
13323 }
13324 } else {
13325 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13326 res = ast_play_and_wait(chan, "vm-sorry");
13327 }
13328 ast_config_destroy(msg_cfg);
13329 return res;
13330 case '*':
13331 res = 't';
13332 break;
13333 case '3':
13334 case '4':
13335 case '5':
13336 case '6':
13337 case '7':
13338 case '8':
13339 case '9':
13340 case '0':
13341
13342 res = ast_play_and_wait(chan, "vm-sorry");
13343 retries++;
13344 break;
13345 default:
13346 if (num) {
13347 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13348 res = ast_play_and_wait(chan, "vm-num-i-have");
13349 if (!res)
13350 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13351 if (!res)
13352 res = ast_play_and_wait(chan, "vm-tocallnum");
13353
13354 if (!ast_strlen_zero(vmu->dialout)) {
13355 if (!res)
13356 res = ast_play_and_wait(chan, "vm-calldiffnum");
13357 }
13358 } else {
13359 res = ast_play_and_wait(chan, "vm-nonumber");
13360 if (!ast_strlen_zero(vmu->dialout)) {
13361 if (!res)
13362 res = ast_play_and_wait(chan, "vm-toenternumber");
13363 }
13364 }
13365 if (!res) {
13366 res = ast_play_and_wait(chan, "vm-star-cancel");
13367 }
13368 if (!res) {
13369 res = ast_waitfordigit(chan, 6000);
13370 }
13371 if (!res) {
13372 retries++;
13373 if (retries > 3) {
13374 res = 't';
13375 }
13376 }
13377 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13378 break;
13379
13380 }
13381 if (res == 't')
13382 res = 0;
13383 else if (res == '*')
13384 res = -1;
13385 }
13386 break;
13387
13388 case 1:
13389
13390 if (ast_strlen_zero(cid))
13391 break;
13392
13393 ast_callerid_parse(cid, &name, &num);
13394 if (!num) {
13395 ast_verb(3, "No CID number available, no reply sent\n");
13396 if (!res)
13397 res = ast_play_and_wait(chan, "vm-nonumber");
13398 ast_config_destroy(msg_cfg);
13399 return res;
13400 } else {
13401 struct ast_vm_user vmu2;
13402 if (find_user(&vmu2, vmu->context, num)) {
13403 struct leave_vm_options leave_options;
13404 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13405 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13406
13407 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13408
13409 memset(&leave_options, 0, sizeof(leave_options));
13410 leave_options.record_gain = record_gain;
13411 res = leave_voicemail(chan, mailbox, &leave_options);
13412 if (!res)
13413 res = 't';
13414 ast_config_destroy(msg_cfg);
13415 return res;
13416 } else {
13417
13418 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13419 ast_play_and_wait(chan, "vm-nobox");
13420 res = 't';
13421 ast_config_destroy(msg_cfg);
13422 return res;
13423 }
13424 }
13425 res = 0;
13426
13427 break;
13428 }
13429
13430 #ifndef IMAP_STORAGE
13431 ast_config_destroy(msg_cfg);
13432
13433 if (!res) {
13434 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13435 vms->heard[msg] = 1;
13436 res = wait_file(chan, vms, vms->fn);
13437 }
13438 #endif
13439 return res;
13440 }
13441
13442 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13443 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13444 signed char record_gain, struct vm_state *vms, char *flag)
13445 {
13446
13447 int res = 0;
13448 int cmd = 0;
13449 int max_attempts = 3;
13450 int attempts = 0;
13451 int recorded = 0;
13452 int msg_exists = 0;
13453 signed char zero_gain = 0;
13454 char tempfile[PATH_MAX];
13455 char *acceptdtmf = "#";
13456 char *canceldtmf = "";
13457 int canceleddtmf = 0;
13458
13459
13460
13461
13462 if (duration == NULL) {
13463 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13464 return -1;
13465 }
13466
13467 if (!outsidecaller)
13468 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13469 else
13470 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13471
13472 cmd = '3';
13473
13474 while ((cmd >= 0) && (cmd != 't')) {
13475 switch (cmd) {
13476 case '1':
13477 if (!msg_exists) {
13478
13479 cmd = '3';
13480 break;
13481 } else {
13482
13483 ast_verb(3, "Saving message as is\n");
13484 if (!outsidecaller)
13485 ast_filerename(tempfile, recordfile, NULL);
13486 ast_stream_and_wait(chan, "vm-msgsaved", "");
13487 if (!outsidecaller) {
13488
13489 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13490 DISPOSE(recordfile, -1);
13491 }
13492 cmd = 't';
13493 return res;
13494 }
13495 case '2':
13496
13497 ast_verb(3, "Reviewing the message\n");
13498 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13499 break;
13500 case '3':
13501 msg_exists = 0;
13502
13503 if (recorded == 1)
13504 ast_verb(3, "Re-recording the message\n");
13505 else
13506 ast_verb(3, "Recording the message\n");
13507
13508 if (recorded && outsidecaller) {
13509 cmd = ast_play_and_wait(chan, INTRO);
13510 cmd = ast_play_and_wait(chan, "beep");
13511 }
13512 recorded = 1;
13513
13514 if (record_gain)
13515 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13516 if (ast_test_flag(vmu, VM_OPERATOR))
13517 canceldtmf = "0";
13518 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13519 if (strchr(canceldtmf, cmd)) {
13520
13521 canceleddtmf = 1;
13522 }
13523 if (record_gain)
13524 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13525 if (cmd == -1) {
13526
13527 if (!outsidecaller) {
13528
13529 ast_filedelete(tempfile, NULL);
13530 }
13531 return cmd;
13532 }
13533 if (cmd == '0') {
13534 break;
13535 } else if (cmd == '*') {
13536 break;
13537 #if 0
13538 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13539
13540 ast_verb(3, "Message too short\n");
13541 cmd = ast_play_and_wait(chan, "vm-tooshort");
13542 cmd = ast_filedelete(tempfile, NULL);
13543 break;
13544 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13545
13546 ast_verb(3, "Nothing recorded\n");
13547 cmd = ast_filedelete(tempfile, NULL);
13548 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13549 if (!cmd)
13550 cmd = ast_play_and_wait(chan, "vm-speakup");
13551 break;
13552 #endif
13553 } else {
13554
13555 msg_exists = 1;
13556 cmd = 0;
13557 }
13558 break;
13559 case '4':
13560 if (outsidecaller) {
13561
13562 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13563 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13564 res = ast_play_and_wait(chan, "vm-marked-urgent");
13565 strcpy(flag, "Urgent");
13566 } else if (flag) {
13567 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13568 res = ast_play_and_wait(chan, "vm-urgent-removed");
13569 strcpy(flag, "");
13570 } else {
13571 ast_play_and_wait(chan, "vm-sorry");
13572 }
13573 cmd = 0;
13574 } else {
13575 cmd = ast_play_and_wait(chan, "vm-sorry");
13576 }
13577 break;
13578 case '5':
13579 case '6':
13580 case '7':
13581 case '8':
13582 case '9':
13583 case '*':
13584 case '#':
13585 cmd = ast_play_and_wait(chan, "vm-sorry");
13586 break;
13587 #if 0
13588
13589
13590 case '*':
13591
13592 cmd = ast_play_and_wait(chan, "vm-deleted");
13593 cmd = ast_filedelete(tempfile, NULL);
13594 if (outsidecaller) {
13595 res = vm_exec(chan, NULL);
13596 return res;
13597 }
13598 else
13599 return 1;
13600 #endif
13601 case '0':
13602 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13603 cmd = ast_play_and_wait(chan, "vm-sorry");
13604 break;
13605 }
13606 if (msg_exists || recorded) {
13607 cmd = ast_play_and_wait(chan, "vm-saveoper");
13608 if (!cmd)
13609 cmd = ast_waitfordigit(chan, 3000);
13610 if (cmd == '1') {
13611 ast_filerename(tempfile, recordfile, NULL);
13612 ast_play_and_wait(chan, "vm-msgsaved");
13613 cmd = '0';
13614 } else if (cmd == '4') {
13615 if (flag) {
13616 ast_play_and_wait(chan, "vm-marked-urgent");
13617 strcpy(flag, "Urgent");
13618 }
13619 ast_play_and_wait(chan, "vm-msgsaved");
13620 cmd = '0';
13621 } else {
13622 ast_play_and_wait(chan, "vm-deleted");
13623 DELETE(tempfile, -1, tempfile, vmu);
13624 cmd = '0';
13625 }
13626 }
13627 return cmd;
13628 default:
13629
13630
13631
13632 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13633 return cmd;
13634 if (msg_exists) {
13635 cmd = ast_play_and_wait(chan, "vm-review");
13636 if (!cmd && outsidecaller) {
13637 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13638 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13639 } else if (flag) {
13640 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13641 }
13642 }
13643 } else {
13644 cmd = ast_play_and_wait(chan, "vm-torerecord");
13645 if (!cmd)
13646 cmd = ast_waitfordigit(chan, 600);
13647 }
13648
13649 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13650 cmd = ast_play_and_wait(chan, "vm-reachoper");
13651 if (!cmd)
13652 cmd = ast_waitfordigit(chan, 600);
13653 }
13654 #if 0
13655 if (!cmd)
13656 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13657 #endif
13658 if (!cmd)
13659 cmd = ast_waitfordigit(chan, 6000);
13660 if (!cmd) {
13661 attempts++;
13662 }
13663 if (attempts > max_attempts) {
13664 cmd = 't';
13665 }
13666 }
13667 }
13668 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13669
13670 ast_filedelete(tempfile, NULL);
13671 }
13672
13673 if (cmd != 't' && outsidecaller)
13674 ast_play_and_wait(chan, "vm-goodbye");
13675
13676 return cmd;
13677 }
13678
13679
13680
13681
13682
13683 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13684 .load = load_module,
13685 .unload = unload_module,
13686 .reload = reload,
13687 .nonoptreq = "res_adsi,res_smdi",
13688 );