00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 #include "asterisk.h"
00074
00075 #ifdef IMAP_STORAGE
00076 #include <ctype.h>
00077 #include <signal.h>
00078 #include <pwd.h>
00079 #ifdef USE_SYSTEM_IMAP
00080 #include <imap/c-client.h>
00081 #include <imap/imap4r1.h>
00082 #include <imap/linkage.h>
00083 #elif defined (USE_SYSTEM_CCLIENT)
00084 #include <c-client/c-client.h>
00085 #include <c-client/imap4r1.h>
00086 #include <c-client/linkage.h>
00087 #else
00088 #include "c-client.h"
00089 #include "imap4r1.h"
00090 #include "linkage.h"
00091 #endif
00092 #endif
00093
00094 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426691 $")
00095
00096 #include "asterisk/paths.h"
00097 #include <sys/time.h>
00098 #include <sys/stat.h>
00099 #include <sys/mman.h>
00100 #include <time.h>
00101 #include <dirent.h>
00102 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00103 #include <sys/wait.h>
00104 #endif
00105
00106 #include "asterisk/logger.h"
00107 #include "asterisk/lock.h"
00108 #include "asterisk/file.h"
00109 #include "asterisk/channel.h"
00110 #include "asterisk/pbx.h"
00111 #include "asterisk/config.h"
00112 #include "asterisk/say.h"
00113 #include "asterisk/module.h"
00114 #include "asterisk/adsi.h"
00115 #include "asterisk/app.h"
00116 #include "asterisk/manager.h"
00117 #include "asterisk/dsp.h"
00118 #include "asterisk/localtime.h"
00119 #include "asterisk/cli.h"
00120 #include "asterisk/utils.h"
00121 #include "asterisk/stringfields.h"
00122 #include "asterisk/smdi.h"
00123 #include "asterisk/astobj2.h"
00124 #include "asterisk/event.h"
00125 #include "asterisk/taskprocessor.h"
00126 #include "asterisk/test.h"
00127
00128 #ifdef ODBC_STORAGE
00129 #include "asterisk/res_odbc.h"
00130 #endif
00131
00132 #ifdef IMAP_STORAGE
00133 #include "asterisk/threadstorage.h"
00134 #endif
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 #ifdef IMAP_STORAGE
00375 static char imapserver[48];
00376 static char imapport[8];
00377 static char imapflags[128];
00378 static char imapfolder[64];
00379 static char imapparentfolder[64] = "\0";
00380 static char greetingfolder[64];
00381 static char authuser[32];
00382 static char authpassword[42];
00383 static int imapversion = 1;
00384
00385 static int expungeonhangup = 1;
00386 static int imapgreetings = 0;
00387 static char delimiter = '\0';
00388
00389 struct vm_state;
00390 struct ast_vm_user;
00391
00392 AST_THREADSTORAGE(ts_vmstate);
00393
00394
00395 static int init_mailstream(struct vm_state *vms, int box);
00396 static void write_file(char *filename, char *buffer, unsigned long len);
00397 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00398 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00399 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00400 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00401 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00402 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00403 static void vmstate_insert(struct vm_state *vms);
00404 static void vmstate_delete(struct vm_state *vms);
00405 static void set_update(MAILSTREAM * stream);
00406 static void init_vm_state(struct vm_state *vms);
00407 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00408 static void get_mailbox_delimiter(MAILSTREAM *stream);
00409 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00410 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00411 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag);
00412 static void update_messages_by_imapuser(const char *user, unsigned long number);
00413 static int vm_delete(char *file);
00414
00415 static int imap_remove_file (char *dir, int msgnum);
00416 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00417 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00418 static void check_quota(struct vm_state *vms, char *mailbox);
00419 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00420 struct vmstate {
00421 struct vm_state *vms;
00422 AST_LIST_ENTRY(vmstate) list;
00423 };
00424
00425 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00426
00427 #endif
00428
00429 #define SMDI_MWI_WAIT_TIMEOUT 1000
00430
00431 #define COMMAND_TIMEOUT 5000
00432
00433 #define VOICEMAIL_DIR_MODE 0777
00434 #define VOICEMAIL_FILE_MODE 0666
00435 #define CHUNKSIZE 65536
00436
00437 #define VOICEMAIL_CONFIG "voicemail.conf"
00438 #define ASTERISK_USERNAME "asterisk"
00439
00440
00441
00442
00443 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00444 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00445 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00446 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00447 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00448 #define VALID_DTMF "1234567890*#"
00449
00450
00451
00452 #define SENDMAIL "/usr/sbin/sendmail -t"
00453
00454 #define INTRO "vm-intro"
00455
00456 #define MAXMSG 100
00457 #define MAXMSGLIMIT 9999
00458
00459 #define MINPASSWORD 0
00460
00461 #define BASELINELEN 72
00462 #define BASEMAXINLINE 256
00463 #ifdef IMAP_STORAGE
00464 #define ENDL "\r\n"
00465 #else
00466 #define ENDL "\n"
00467 #endif
00468
00469 #define MAX_DATETIME_FORMAT 512
00470 #define MAX_NUM_CID_CONTEXTS 10
00471
00472 #define VM_REVIEW (1 << 0)
00473 #define VM_OPERATOR (1 << 1)
00474 #define VM_SAYCID (1 << 2)
00475 #define VM_SVMAIL (1 << 3)
00476 #define VM_ENVELOPE (1 << 4)
00477 #define VM_SAYDURATION (1 << 5)
00478 #define VM_SKIPAFTERCMD (1 << 6)
00479 #define VM_FORCENAME (1 << 7)
00480 #define VM_FORCEGREET (1 << 8)
00481 #define VM_PBXSKIP (1 << 9)
00482 #define VM_DIRECFORWARD (1 << 10)
00483 #define VM_ATTACH (1 << 11)
00484 #define VM_DELETE (1 << 12)
00485 #define VM_ALLOCED (1 << 13)
00486 #define VM_SEARCH (1 << 14)
00487 #define VM_TEMPGREETWARN (1 << 15)
00488 #define VM_MOVEHEARD (1 << 16)
00489 #define VM_MESSAGEWRAP (1 << 17)
00490 #define VM_FWDURGAUTO (1 << 18)
00491 #define ERROR_LOCK_PATH -100
00492 #define OPERATOR_EXIT 300
00493
00494
00495 enum vm_box {
00496 NEW_FOLDER,
00497 OLD_FOLDER,
00498 WORK_FOLDER,
00499 FAMILY_FOLDER,
00500 FRIENDS_FOLDER,
00501 GREETINGS_FOLDER
00502 };
00503
00504 enum vm_option_flags {
00505 OPT_SILENT = (1 << 0),
00506 OPT_BUSY_GREETING = (1 << 1),
00507 OPT_UNAVAIL_GREETING = (1 << 2),
00508 OPT_RECORDGAIN = (1 << 3),
00509 OPT_PREPEND_MAILBOX = (1 << 4),
00510 OPT_AUTOPLAY = (1 << 6),
00511 OPT_DTMFEXIT = (1 << 7),
00512 OPT_MESSAGE_Urgent = (1 << 8),
00513 OPT_MESSAGE_PRIORITY = (1 << 9)
00514 };
00515
00516 enum vm_option_args {
00517 OPT_ARG_RECORDGAIN = 0,
00518 OPT_ARG_PLAYFOLDER = 1,
00519 OPT_ARG_DTMFEXIT = 2,
00520
00521 OPT_ARG_ARRAY_SIZE = 3,
00522 };
00523
00524 enum vm_passwordlocation {
00525 OPT_PWLOC_VOICEMAILCONF = 0,
00526 OPT_PWLOC_SPOOLDIR = 1,
00527 OPT_PWLOC_USERSCONF = 2,
00528 };
00529
00530 AST_APP_OPTIONS(vm_app_options, {
00531 AST_APP_OPTION('s', OPT_SILENT),
00532 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00533 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00534 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00535 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00536 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00537 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00538 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00539 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00540 });
00541
00542 static int load_config(int reload);
00543 #ifdef TEST_FRAMEWORK
00544 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00545 #endif
00546 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 struct baseio {
00632 int iocp;
00633 int iolen;
00634 int linelength;
00635 int ateof;
00636 unsigned char iobuf[BASEMAXINLINE];
00637 };
00638
00639
00640
00641 struct ast_vm_user {
00642 char context[AST_MAX_CONTEXT];
00643 char mailbox[AST_MAX_EXTENSION];
00644 char password[80];
00645 char fullname[80];
00646 char email[80];
00647 char *emailsubject;
00648 char *emailbody;
00649 char pager[80];
00650 char serveremail[80];
00651 char language[MAX_LANGUAGE];
00652 char zonetag[80];
00653 char locale[20];
00654 char callback[80];
00655 char dialout[80];
00656 char uniqueid[80];
00657 char exit[80];
00658 char attachfmt[20];
00659 unsigned int flags;
00660 int saydurationm;
00661 int minsecs;
00662 int maxmsg;
00663 int maxdeletedmsg;
00664 int maxsecs;
00665 int passwordlocation;
00666 #ifdef IMAP_STORAGE
00667 char imapuser[80];
00668 char imappassword[80];
00669 char imapfolder[64];
00670 char imapvmshareid[80];
00671 int imapversion;
00672 #endif
00673 double volgain;
00674 AST_LIST_ENTRY(ast_vm_user) list;
00675 };
00676
00677
00678 struct vm_zone {
00679 AST_LIST_ENTRY(vm_zone) list;
00680 char name[80];
00681 char timezone[80];
00682 char msg_format[512];
00683 };
00684
00685 #define VMSTATE_MAX_MSG_ARRAY 256
00686
00687
00688 struct vm_state {
00689 char curbox[80];
00690 char username[80];
00691 char context[80];
00692 char curdir[PATH_MAX];
00693 char vmbox[PATH_MAX];
00694 char fn[PATH_MAX];
00695 char intro[PATH_MAX];
00696 int *deleted;
00697 int *heard;
00698 int dh_arraysize;
00699 int curmsg;
00700 int lastmsg;
00701 int newmessages;
00702 int oldmessages;
00703 int urgentmessages;
00704 int starting;
00705 int repeats;
00706 #ifdef IMAP_STORAGE
00707 ast_mutex_t lock;
00708 int updated;
00709 long *msgArray;
00710 unsigned msg_array_max;
00711 MAILSTREAM *mailstream;
00712 int vmArrayIndex;
00713 char imapuser[80];
00714 char imapfolder[64];
00715 int imapversion;
00716 int interactive;
00717 char introfn[PATH_MAX];
00718 unsigned int quota_limit;
00719 unsigned int quota_usage;
00720 struct vm_state *persist_vms;
00721 #endif
00722 };
00723
00724 #ifdef ODBC_STORAGE
00725 static char odbc_database[80];
00726 static char odbc_table[80];
00727 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00728 #define DISPOSE(a,b) remove_file(a,b)
00729 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00730 #define EXISTS(a,b,c,d) (message_exists(a,b))
00731 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00732 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00733 #define DELETE(a,b,c,d) (delete_file(a,b))
00734 #else
00735 #ifdef IMAP_STORAGE
00736 #define DISPOSE(a,b) (imap_remove_file(a,b))
00737 #define STORE(a,b,c,d,e,f,g,h,i,j) (imap_store_file(a,b,c,d,e,f,g,h,i,j))
00738 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00739 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00740 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00741 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00742 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00743 #else
00744 #define RETRIEVE(a,b,c,d)
00745 #define DISPOSE(a,b)
00746 #define STORE(a,b,c,d,e,f,g,h,i,j)
00747 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00748 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00749 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00750 #define DELETE(a,b,c,d) (vm_delete(c))
00751 #endif
00752 #endif
00753
00754 static char VM_SPOOL_DIR[PATH_MAX];
00755
00756 static char ext_pass_cmd[128];
00757 static char ext_pass_check_cmd[128];
00758
00759 static int my_umask;
00760
00761 #define PWDCHANGE_INTERNAL (1 << 1)
00762 #define PWDCHANGE_EXTERNAL (1 << 2)
00763 static int pwdchange = PWDCHANGE_INTERNAL;
00764
00765 #ifdef ODBC_STORAGE
00766 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00767 #else
00768 # ifdef IMAP_STORAGE
00769 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00770 # else
00771 # define tdesc "Comedian Mail (Voicemail System)"
00772 # endif
00773 #endif
00774
00775 static char userscontext[AST_MAX_EXTENSION] = "default";
00776
00777 static char *addesc = "Comedian Mail";
00778
00779
00780 static char *app = "VoiceMail";
00781
00782
00783 static char *app2 = "VoiceMailMain";
00784
00785 static char *app3 = "MailboxExists";
00786 static char *app4 = "VMAuthenticate";
00787
00788 static char *sayname_app = "VMSayName";
00789
00790 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00791 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00792 static char zonetag[80];
00793 static char locale[20];
00794 static int maxsilence;
00795 static int maxmsg;
00796 static int maxdeletedmsg;
00797 static int silencethreshold = 128;
00798 static char serveremail[80];
00799 static char mailcmd[160];
00800 static char externnotify[160];
00801 static struct ast_smdi_interface *smdi_iface = NULL;
00802 static char vmfmts[80];
00803 static double volgain;
00804 static int vmminsecs;
00805 static int vmmaxsecs;
00806 static int maxgreet;
00807 static int skipms;
00808 static int maxlogins;
00809 static int minpassword;
00810 static int passwordlocation;
00811
00812
00813
00814 static unsigned int poll_mailboxes;
00815
00816
00817 static unsigned int poll_freq;
00818
00819 #define DEFAULT_POLL_FREQ 30
00820
00821 AST_MUTEX_DEFINE_STATIC(poll_lock);
00822 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00823 static pthread_t poll_thread = AST_PTHREADT_NULL;
00824 static unsigned char poll_thread_run;
00825
00826
00827 static struct ast_event_sub *mwi_sub_sub;
00828
00829 static struct ast_event_sub *mwi_unsub_sub;
00830
00831
00832
00833
00834
00835
00836
00837
00838 struct mwi_sub {
00839 AST_RWLIST_ENTRY(mwi_sub) entry;
00840 int old_urgent;
00841 int old_new;
00842 int old_old;
00843 uint32_t uniqueid;
00844 char mailbox[1];
00845 };
00846
00847 struct mwi_sub_task {
00848 const char *mailbox;
00849 const char *context;
00850 uint32_t uniqueid;
00851 };
00852
00853 static struct ast_taskprocessor *mwi_subscription_tps;
00854
00855 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00856
00857
00858 static char listen_control_forward_key[12];
00859 static char listen_control_reverse_key[12];
00860 static char listen_control_pause_key[12];
00861 static char listen_control_restart_key[12];
00862 static char listen_control_stop_key[12];
00863
00864
00865 static char vm_password[80] = "vm-password";
00866 static char vm_newpassword[80] = "vm-newpassword";
00867 static char vm_passchanged[80] = "vm-passchanged";
00868 static char vm_reenterpassword[80] = "vm-reenterpassword";
00869 static char vm_mismatch[80] = "vm-mismatch";
00870 static char vm_invalid_password[80] = "vm-invalid-password";
00871 static char vm_pls_try_again[80] = "vm-pls-try-again";
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883 static char vm_prepend_timeout[80] = "vm-then-pound";
00884
00885 static struct ast_flags globalflags = {0};
00886
00887 static int saydurationminfo;
00888
00889 static char dialcontext[AST_MAX_CONTEXT] = "";
00890 static char callcontext[AST_MAX_CONTEXT] = "";
00891 static char exitcontext[AST_MAX_CONTEXT] = "";
00892
00893 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00894
00895
00896 static char *emailbody = NULL;
00897 static char *emailsubject = NULL;
00898 static char *pagerbody = NULL;
00899 static char *pagersubject = NULL;
00900 static char fromstring[100];
00901 static char pagerfromstring[100];
00902 static char charset[32] = "ISO-8859-1";
00903
00904 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00905 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00906 static int adsiver = 1;
00907 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00908 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00909
00910
00911 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00912 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain);
00913 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00914 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00915 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00916 signed char record_gain, struct vm_state *vms, char *flag);
00917 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00918 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00919 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag);
00920 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag);
00921 static void apply_options(struct ast_vm_user *vmu, const char *options);
00922 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum);
00923 static int is_valid_dtmf(const char *key);
00924 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00925 static int write_password_to_file(const char *secretfn, const char *password);
00926 static const char *substitute_escapes(const char *value);
00927 static void free_user(struct ast_vm_user *vmu);
00928
00929 struct ao2_container *inprocess_container;
00930
00931 struct inprocess {
00932 int count;
00933 char *context;
00934 char mailbox[0];
00935 };
00936
00937 static int inprocess_hash_fn(const void *obj, const int flags)
00938 {
00939 const struct inprocess *i = obj;
00940 return atoi(i->mailbox);
00941 }
00942
00943 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00944 {
00945 struct inprocess *i = obj, *j = arg;
00946 if (strcmp(i->mailbox, j->mailbox)) {
00947 return 0;
00948 }
00949 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00950 }
00951
00952 static int inprocess_count(const char *context, const char *mailbox, int delta)
00953 {
00954 struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00955 arg->context = arg->mailbox + strlen(mailbox) + 1;
00956 strcpy(arg->mailbox, mailbox);
00957 strcpy(arg->context, context);
00958 ao2_lock(inprocess_container);
00959 if ((i = ao2_find(inprocess_container, arg, 0))) {
00960 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00961 ao2_unlock(inprocess_container);
00962 ao2_ref(i, -1);
00963 return ret;
00964 }
00965 if (delta < 0) {
00966 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00967 }
00968 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00969 ao2_unlock(inprocess_container);
00970 return 0;
00971 }
00972 i->context = i->mailbox + strlen(mailbox) + 1;
00973 strcpy(i->mailbox, mailbox);
00974 strcpy(i->context, context);
00975 i->count = delta;
00976 ao2_link(inprocess_container, i);
00977 ao2_unlock(inprocess_container);
00978 ao2_ref(i, -1);
00979 return 0;
00980 }
00981
00982 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00983 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00984 #endif
00985
00986
00987
00988
00989
00990
00991
00992 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00993 {
00994 char *bufptr = buf;
00995 for (; *input; input++) {
00996 if (*input < 32) {
00997 continue;
00998 }
00999 *bufptr++ = *input;
01000 if (bufptr == buf + buflen - 1) {
01001 break;
01002 }
01003 }
01004 *bufptr = '\0';
01005 return buf;
01006 }
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022 static void populate_defaults(struct ast_vm_user *vmu)
01023 {
01024 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01025 vmu->passwordlocation = passwordlocation;
01026 if (saydurationminfo) {
01027 vmu->saydurationm = saydurationminfo;
01028 }
01029 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01030 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01031 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01032 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01033 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01034 if (vmminsecs) {
01035 vmu->minsecs = vmminsecs;
01036 }
01037 if (vmmaxsecs) {
01038 vmu->maxsecs = vmmaxsecs;
01039 }
01040 if (maxmsg) {
01041 vmu->maxmsg = maxmsg;
01042 }
01043 if (maxdeletedmsg) {
01044 vmu->maxdeletedmsg = maxdeletedmsg;
01045 }
01046 vmu->volgain = volgain;
01047 ast_free(vmu->emailsubject);
01048 vmu->emailsubject = NULL;
01049 ast_free(vmu->emailbody);
01050 vmu->emailbody = NULL;
01051 #ifdef IMAP_STORAGE
01052 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01053 #endif
01054 }
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01065 {
01066 int x;
01067 if (!strcasecmp(var, "attach")) {
01068 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01069 } else if (!strcasecmp(var, "attachfmt")) {
01070 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01071 } else if (!strcasecmp(var, "serveremail")) {
01072 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01073 } else if (!strcasecmp(var, "emailbody")) {
01074 vmu->emailbody = ast_strdup(substitute_escapes(value));
01075 } else if (!strcasecmp(var, "emailsubject")) {
01076 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01077 } else if (!strcasecmp(var, "language")) {
01078 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01079 } else if (!strcasecmp(var, "tz")) {
01080 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01081 } else if (!strcasecmp(var, "locale")) {
01082 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01083 #ifdef IMAP_STORAGE
01084 } else if (!strcasecmp(var, "imapuser")) {
01085 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01086 vmu->imapversion = imapversion;
01087 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01088 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01089 vmu->imapversion = imapversion;
01090 } else if (!strcasecmp(var, "imapfolder")) {
01091 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01092 } else if (!strcasecmp(var, "imapvmshareid")) {
01093 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01094 vmu->imapversion = imapversion;
01095 #endif
01096 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01097 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01098 } else if (!strcasecmp(var, "saycid")){
01099 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01100 } else if (!strcasecmp(var, "sendvoicemail")){
01101 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01102 } else if (!strcasecmp(var, "review")){
01103 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01104 } else if (!strcasecmp(var, "tempgreetwarn")){
01105 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01106 } else if (!strcasecmp(var, "messagewrap")){
01107 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01108 } else if (!strcasecmp(var, "operator")) {
01109 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01110 } else if (!strcasecmp(var, "envelope")){
01111 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01112 } else if (!strcasecmp(var, "moveheard")){
01113 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01114 } else if (!strcasecmp(var, "sayduration")){
01115 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01116 } else if (!strcasecmp(var, "saydurationm")){
01117 if (sscanf(value, "%30d", &x) == 1) {
01118 vmu->saydurationm = x;
01119 } else {
01120 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01121 }
01122 } else if (!strcasecmp(var, "forcename")){
01123 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01124 } else if (!strcasecmp(var, "forcegreetings")){
01125 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01126 } else if (!strcasecmp(var, "callback")) {
01127 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01128 } else if (!strcasecmp(var, "dialout")) {
01129 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01130 } else if (!strcasecmp(var, "exitcontext")) {
01131 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01132 } else if (!strcasecmp(var, "minsecs")) {
01133 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01134 vmu->minsecs = x;
01135 } else {
01136 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01137 vmu->minsecs = vmminsecs;
01138 }
01139 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01140 vmu->maxsecs = atoi(value);
01141 if (vmu->maxsecs <= 0) {
01142 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01143 vmu->maxsecs = vmmaxsecs;
01144 } else {
01145 vmu->maxsecs = atoi(value);
01146 }
01147 if (!strcasecmp(var, "maxmessage"))
01148 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01149 } else if (!strcasecmp(var, "maxmsg")) {
01150 vmu->maxmsg = atoi(value);
01151
01152 if (vmu->maxmsg < 0) {
01153 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01154 vmu->maxmsg = MAXMSG;
01155 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01156 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01157 vmu->maxmsg = MAXMSGLIMIT;
01158 }
01159 } else if (!strcasecmp(var, "nextaftercmd")) {
01160 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01161 } else if (!strcasecmp(var, "backupdeleted")) {
01162 if (sscanf(value, "%30d", &x) == 1)
01163 vmu->maxdeletedmsg = x;
01164 else if (ast_true(value))
01165 vmu->maxdeletedmsg = MAXMSG;
01166 else
01167 vmu->maxdeletedmsg = 0;
01168
01169 if (vmu->maxdeletedmsg < 0) {
01170 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01171 vmu->maxdeletedmsg = MAXMSG;
01172 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01173 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01174 vmu->maxdeletedmsg = MAXMSGLIMIT;
01175 }
01176 } else if (!strcasecmp(var, "volgain")) {
01177 sscanf(value, "%30lf", &vmu->volgain);
01178 } else if (!strcasecmp(var, "passwordlocation")) {
01179 if (!strcasecmp(value, "spooldir")) {
01180 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01181 } else {
01182 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01183 }
01184 } else if (!strcasecmp(var, "options")) {
01185 apply_options(vmu, value);
01186 }
01187 }
01188
01189 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01190 {
01191 int fds[2], pid = 0;
01192
01193 memset(buf, 0, len);
01194
01195 if (pipe(fds)) {
01196 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01197 } else {
01198
01199 pid = ast_safe_fork(0);
01200
01201 if (pid < 0) {
01202
01203 close(fds[0]);
01204 close(fds[1]);
01205 snprintf(buf, len, "FAILURE: Fork failed");
01206 } else if (pid) {
01207
01208 close(fds[1]);
01209 if (read(fds[0], buf, len) < 0) {
01210 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01211 }
01212 close(fds[0]);
01213 } else {
01214
01215 AST_DECLARE_APP_ARGS(arg,
01216 AST_APP_ARG(v)[20];
01217 );
01218 char *mycmd = ast_strdupa(command);
01219
01220 close(fds[0]);
01221 dup2(fds[1], STDOUT_FILENO);
01222 close(fds[1]);
01223 ast_close_fds_above_n(STDOUT_FILENO);
01224
01225 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01226
01227 execv(arg.v[0], arg.v);
01228 printf("FAILURE: %s", strerror(errno));
01229 _exit(0);
01230 }
01231 }
01232 return buf;
01233 }
01234
01235
01236
01237
01238
01239
01240
01241
01242 static int check_password(struct ast_vm_user *vmu, char *password)
01243 {
01244
01245 if (strlen(password) < minpassword)
01246 return 1;
01247
01248 if (!ast_strlen_zero(password) && password[0] == '*')
01249 return 1;
01250 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01251 char cmd[255], buf[255];
01252
01253 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01254
01255 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01256 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01257 ast_debug(5, "Result: %s\n", buf);
01258 if (!strncasecmp(buf, "VALID", 5)) {
01259 ast_debug(3, "Passed password check: '%s'\n", buf);
01260 return 0;
01261 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01262 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01263 return 0;
01264 } else {
01265 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01266 return 1;
01267 }
01268 }
01269 }
01270 return 0;
01271 }
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01284 {
01285 int res = -1;
01286 if (!strcmp(vmu->password, password)) {
01287
01288 return 0;
01289 }
01290
01291 if (strlen(password) > 10) {
01292 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01293 }
01294 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01295 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01296 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01297 res = 0;
01298 }
01299 return res;
01300 }
01301
01302
01303
01304
01305 static void apply_options(struct ast_vm_user *vmu, const char *options)
01306 {
01307 char *stringp;
01308 char *s;
01309 char *var, *value;
01310 stringp = ast_strdupa(options);
01311 while ((s = strsep(&stringp, "|"))) {
01312 value = s;
01313 if ((var = strsep(&value, "=")) && value) {
01314 apply_option(vmu, var, value);
01315 }
01316 }
01317 }
01318
01319
01320
01321
01322
01323
01324 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01325 {
01326 for (; var; var = var->next) {
01327 if (!strcasecmp(var->name, "vmsecret")) {
01328 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01329 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01330 if (ast_strlen_zero(retval->password)) {
01331 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01332 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01333 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01334 } else {
01335 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01336 }
01337 }
01338 } else if (!strcasecmp(var->name, "uniqueid")) {
01339 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01340 } else if (!strcasecmp(var->name, "pager")) {
01341 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01342 } else if (!strcasecmp(var->name, "email")) {
01343 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01344 } else if (!strcasecmp(var->name, "fullname")) {
01345 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01346 } else if (!strcasecmp(var->name, "context")) {
01347 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01348 } else if (!strcasecmp(var->name, "emailsubject")) {
01349 ast_free(retval->emailsubject);
01350 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01351 } else if (!strcasecmp(var->name, "emailbody")) {
01352 ast_free(retval->emailbody);
01353 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01354 #ifdef IMAP_STORAGE
01355 } else if (!strcasecmp(var->name, "imapuser")) {
01356 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01357 retval->imapversion = imapversion;
01358 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01359 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01360 retval->imapversion = imapversion;
01361 } else if (!strcasecmp(var->name, "imapfolder")) {
01362 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01363 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01364 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01365 retval->imapversion = imapversion;
01366 #endif
01367 } else
01368 apply_option(retval, var->name, var->value);
01369 }
01370 }
01371
01372
01373
01374
01375
01376
01377
01378
01379 static int is_valid_dtmf(const char *key)
01380 {
01381 int i;
01382 char *local_key = ast_strdupa(key);
01383
01384 for (i = 0; i < strlen(key); ++i) {
01385 if (!strchr(VALID_DTMF, *local_key)) {
01386 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01387 return 0;
01388 }
01389 local_key++;
01390 }
01391 return 1;
01392 }
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01405 {
01406 struct ast_variable *var;
01407 struct ast_vm_user *retval;
01408
01409 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01410 if (ivm) {
01411 memset(retval, 0, sizeof(*retval));
01412 }
01413 populate_defaults(retval);
01414 if (!ivm) {
01415 ast_set_flag(retval, VM_ALLOCED);
01416 }
01417 if (mailbox) {
01418 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01419 }
01420 if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
01421 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01422 } else {
01423 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01424 }
01425 if (var) {
01426 apply_options_full(retval, var);
01427 ast_variables_destroy(var);
01428 } else {
01429 if (!ivm)
01430 free_user(retval);
01431 retval = NULL;
01432 }
01433 }
01434 return retval;
01435 }
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01446 {
01447
01448 struct ast_vm_user *vmu = NULL, *cur;
01449 AST_LIST_LOCK(&users);
01450
01451 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01452 context = "default";
01453
01454 AST_LIST_TRAVERSE(&users, cur, list) {
01455 #ifdef IMAP_STORAGE
01456 if (cur->imapversion != imapversion) {
01457 continue;
01458 }
01459 #endif
01460 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01461 break;
01462 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01463 break;
01464 }
01465 if (cur) {
01466
01467 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01468 *vmu = *cur;
01469 if (!ivm) {
01470 vmu->emailbody = ast_strdup(cur->emailbody);
01471 vmu->emailsubject = ast_strdup(cur->emailsubject);
01472 }
01473 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01474 AST_LIST_NEXT(vmu, list) = NULL;
01475 }
01476 } else
01477 vmu = find_user_realtime(ivm, context, mailbox);
01478 AST_LIST_UNLOCK(&users);
01479 return vmu;
01480 }
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01493 {
01494
01495 struct ast_vm_user *cur;
01496 int res = -1;
01497 AST_LIST_LOCK(&users);
01498 AST_LIST_TRAVERSE(&users, cur, list) {
01499 if ((!context || !strcasecmp(context, cur->context)) &&
01500 (!strcasecmp(mailbox, cur->mailbox)))
01501 break;
01502 }
01503 if (cur) {
01504 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01505 res = 0;
01506 }
01507 AST_LIST_UNLOCK(&users);
01508 return res;
01509 }
01510
01511
01512
01513
01514 static inline int valid_config(const struct ast_config *cfg)
01515 {
01516 return cfg && cfg != CONFIG_STATUS_FILEINVALID;
01517 }
01518
01519
01520
01521
01522
01523
01524
01525
01526 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01527 {
01528 struct ast_config *cfg = NULL;
01529 struct ast_variable *var = NULL;
01530 struct ast_category *cat = NULL;
01531 char *category = NULL, *value = NULL, *new = NULL;
01532 const char *tmp = NULL;
01533 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01534 char secretfn[PATH_MAX] = "";
01535 int found = 0;
01536
01537 if (!change_password_realtime(vmu, newpassword))
01538 return;
01539
01540
01541 switch (vmu->passwordlocation) {
01542 case OPT_PWLOC_SPOOLDIR:
01543 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01544 if (write_password_to_file(secretfn, newpassword) == 0) {
01545 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01546 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01547 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01548 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01549 break;
01550 } else {
01551 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01552 }
01553
01554 case OPT_PWLOC_VOICEMAILCONF:
01555 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
01556 while ((category = ast_category_browse(cfg, category))) {
01557 if (!strcasecmp(category, vmu->context)) {
01558 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01559 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01560 break;
01561 }
01562 value = strstr(tmp, ",");
01563 if (!value) {
01564 new = ast_alloca(strlen(newpassword)+1);
01565 sprintf(new, "%s", newpassword);
01566 } else {
01567 new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
01568 sprintf(new, "%s%s", newpassword, value);
01569 }
01570 if (!(cat = ast_category_get(cfg, category))) {
01571 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01572 break;
01573 }
01574 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01575 found = 1;
01576 }
01577 }
01578
01579 if (found) {
01580 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01581 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01582 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01583 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01584 ast_config_destroy(cfg);
01585 break;
01586 }
01587
01588 ast_config_destroy(cfg);
01589 }
01590
01591 case OPT_PWLOC_USERSCONF:
01592
01593
01594 if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
01595 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01596 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01597 ast_debug(4, "users.conf: %s\n", category);
01598 if (!strcasecmp(category, vmu->mailbox)) {
01599 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01600 ast_debug(3, "looks like we need to make vmsecret!\n");
01601 var = ast_variable_new("vmsecret", newpassword, "");
01602 } else {
01603 var = NULL;
01604 }
01605 new = ast_alloca(strlen(newpassword) + 1);
01606 sprintf(new, "%s", newpassword);
01607 if (!(cat = ast_category_get(cfg, category))) {
01608 ast_debug(4, "failed to get category!\n");
01609 ast_free(var);
01610 break;
01611 }
01612 if (!var) {
01613 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01614 } else {
01615 ast_variable_append(cat, var);
01616 }
01617 found = 1;
01618 break;
01619 }
01620 }
01621
01622 if (found) {
01623 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01624 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01625 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01626 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01627 }
01628
01629 ast_config_destroy(cfg);
01630 }
01631 }
01632 }
01633
01634 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01635 {
01636 char buf[255];
01637 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01638 ast_debug(1, "External password: %s\n",buf);
01639 if (!ast_safe_system(buf)) {
01640 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01641 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01642
01643 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01644 }
01645 }
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01661 {
01662 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01663 }
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677 static int make_file(char *dest, const int len, const char *dir, const int num)
01678 {
01679 return snprintf(dest, len, "%s/msg%04d", dir, num);
01680 }
01681
01682
01683 static FILE *vm_mkftemp(char *template)
01684 {
01685 FILE *p = NULL;
01686 int pfd = mkstemp(template);
01687 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01688 if (pfd > -1) {
01689 p = fdopen(pfd, "w+");
01690 if (!p) {
01691 close(pfd);
01692 pfd = -1;
01693 }
01694 }
01695 return p;
01696 }
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01707 {
01708 mode_t mode = VOICEMAIL_DIR_MODE;
01709 int res;
01710
01711 make_dir(dest, len, context, ext, folder);
01712 if ((res = ast_mkdir(dest, mode))) {
01713 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01714 return -1;
01715 }
01716 return 0;
01717 }
01718
01719 static const char * const mailbox_folders[] = {
01720 #ifdef IMAP_STORAGE
01721 imapfolder,
01722 #else
01723 "INBOX",
01724 #endif
01725 "Old",
01726 "Work",
01727 "Family",
01728 "Friends",
01729 "Cust1",
01730 "Cust2",
01731 "Cust3",
01732 "Cust4",
01733 "Cust5",
01734 "Deleted",
01735 "Urgent",
01736 };
01737
01738 static const char *mbox(struct ast_vm_user *vmu, int id)
01739 {
01740 #ifdef IMAP_STORAGE
01741 if (vmu && id == 0) {
01742 return vmu->imapfolder;
01743 }
01744 #endif
01745 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01746 }
01747
01748 static int get_folder_by_name(const char *name)
01749 {
01750 size_t i;
01751
01752 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01753 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01754 return i;
01755 }
01756 }
01757
01758 return -1;
01759 }
01760
01761 static void free_user(struct ast_vm_user *vmu)
01762 {
01763 if (ast_test_flag(vmu, VM_ALLOCED)) {
01764
01765 ast_free(vmu->emailbody);
01766 vmu->emailbody = NULL;
01767
01768 ast_free(vmu->emailsubject);
01769 vmu->emailsubject = NULL;
01770
01771 ast_free(vmu);
01772 }
01773 }
01774
01775 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01776
01777 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01778
01779
01780 if (vms->deleted) {
01781 ast_free(vms->deleted);
01782 vms->deleted = NULL;
01783 }
01784 if (vms->heard) {
01785 ast_free(vms->heard);
01786 vms->heard = NULL;
01787 }
01788 vms->dh_arraysize = 0;
01789
01790 if (arraysize > 0) {
01791 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01792 return -1;
01793 }
01794 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01795 ast_free(vms->deleted);
01796 vms->deleted = NULL;
01797 return -1;
01798 }
01799 vms->dh_arraysize = arraysize;
01800 }
01801
01802 return 0;
01803 }
01804
01805
01806
01807 #ifdef IMAP_STORAGE
01808 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01809 {
01810 char arg[10];
01811 struct vm_state *vms;
01812 unsigned long messageNum;
01813
01814
01815 if (msgnum < 0 && !imapgreetings) {
01816 ast_filedelete(file, NULL);
01817 return;
01818 }
01819
01820 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01821 ast_log(LOG_WARNING, "Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->mailbox, msgnum);
01822 return;
01823 }
01824
01825 if (msgnum < 0) {
01826 imap_delete_old_greeting(file, vms);
01827 return;
01828 }
01829
01830
01831
01832 messageNum = vms->msgArray[msgnum];
01833 if (messageNum == 0) {
01834 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01835 return;
01836 }
01837 if (option_debug > 2)
01838 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01839
01840 snprintf (arg, sizeof(arg), "%lu", messageNum);
01841 ast_mutex_lock(&vms->lock);
01842 mail_setflag (vms->mailstream, arg, "\\DELETED");
01843 mail_expunge(vms->mailstream);
01844 ast_mutex_unlock(&vms->lock);
01845 }
01846
01847 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01848 {
01849 struct vm_state *vms_p;
01850 char *file, *filename;
01851 char *attachment;
01852 int i;
01853 BODY *body;
01854
01855
01856
01857
01858 if (msgnum > -1 || !imapgreetings) {
01859 return 0;
01860 } else {
01861 file = strrchr(ast_strdupa(dir), '/');
01862 if (file)
01863 *file++ = '\0';
01864 else {
01865 ast_debug (1, "Failed to procure file name from directory passed.\n");
01866 return -1;
01867 }
01868 }
01869
01870
01871 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01872 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01873
01874
01875
01876
01877 if (!(vms_p = create_vm_state_from_user(vmu))) {
01878 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01879 return -1;
01880 }
01881 }
01882
01883
01884 *vms_p->introfn = '\0';
01885
01886 ast_mutex_lock(&vms_p->lock);
01887 init_mailstream(vms_p, GREETINGS_FOLDER);
01888 if (!vms_p->mailstream) {
01889 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01890 ast_mutex_unlock(&vms_p->lock);
01891 return -1;
01892 }
01893
01894
01895 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01896 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01897
01898 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01899 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01900 } else {
01901 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01902 ast_mutex_unlock(&vms_p->lock);
01903 return -1;
01904 }
01905 filename = strsep(&attachment, ".");
01906 if (!strcmp(filename, file)) {
01907 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01908 vms_p->msgArray[vms_p->curmsg] = i + 1;
01909 save_body(body, vms_p, "2", attachment, 0);
01910 ast_mutex_unlock(&vms_p->lock);
01911 return 0;
01912 }
01913 }
01914 ast_mutex_unlock(&vms_p->lock);
01915
01916 return -1;
01917 }
01918
01919 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01920 {
01921 BODY *body;
01922 char *header_content;
01923 char *attachedfilefmt;
01924 char buf[80];
01925 struct vm_state *vms;
01926 char text_file[PATH_MAX];
01927 FILE *text_file_ptr;
01928 int res = 0;
01929 struct ast_vm_user *vmu;
01930
01931 if (!(vmu = find_user(NULL, context, mailbox))) {
01932 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01933 return -1;
01934 }
01935
01936 if (msgnum < 0) {
01937 if (imapgreetings) {
01938 res = imap_retrieve_greeting(dir, msgnum, vmu);
01939 goto exit;
01940 } else {
01941 res = 0;
01942 goto exit;
01943 }
01944 }
01945
01946
01947
01948
01949 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01950
01951
01952
01953
01954
01955
01956
01957 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01958 res = -1;
01959 goto exit;
01960 }
01961
01962 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01963 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01964
01965
01966 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01967 res = 0;
01968 goto exit;
01969 }
01970
01971 if (option_debug > 2)
01972 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01973 if (vms->msgArray[msgnum] == 0) {
01974 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01975 res = -1;
01976 goto exit;
01977 }
01978
01979
01980 ast_mutex_lock(&vms->lock);
01981 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01982 ast_mutex_unlock(&vms->lock);
01983
01984 if (ast_strlen_zero(header_content)) {
01985 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01986 res = -1;
01987 goto exit;
01988 }
01989
01990 ast_mutex_lock(&vms->lock);
01991 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01992 ast_mutex_unlock(&vms->lock);
01993
01994
01995 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01996 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01997 } else {
01998 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01999 res = -1;
02000 goto exit;
02001 }
02002
02003
02004
02005 strsep(&attachedfilefmt, ".");
02006 if (!attachedfilefmt) {
02007 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
02008 res = -1;
02009 goto exit;
02010 }
02011
02012 save_body(body, vms, "2", attachedfilefmt, 0);
02013 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
02014 *vms->introfn = '\0';
02015 }
02016
02017
02018 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
02019
02020 if (!(text_file_ptr = fopen(text_file, "w"))) {
02021 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
02022 }
02023
02024 fprintf(text_file_ptr, "%s\n", "[message]");
02025
02026 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02027 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02028 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02029 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02030 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02031 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02032 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02033 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02034 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02035 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02036 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02037 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02038 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02039 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02040 fclose(text_file_ptr);
02041
02042 exit:
02043 free_user(vmu);
02044 return res;
02045 }
02046
02047 static int folder_int(const char *folder)
02048 {
02049
02050 if (!folder) {
02051 return 0;
02052 }
02053 if (!strcasecmp(folder, imapfolder)) {
02054 return 0;
02055 } else if (!strcasecmp(folder, "Old")) {
02056 return 1;
02057 } else if (!strcasecmp(folder, "Work")) {
02058 return 2;
02059 } else if (!strcasecmp(folder, "Family")) {
02060 return 3;
02061 } else if (!strcasecmp(folder, "Friends")) {
02062 return 4;
02063 } else if (!strcasecmp(folder, "Cust1")) {
02064 return 5;
02065 } else if (!strcasecmp(folder, "Cust2")) {
02066 return 6;
02067 } else if (!strcasecmp(folder, "Cust3")) {
02068 return 7;
02069 } else if (!strcasecmp(folder, "Cust4")) {
02070 return 8;
02071 } else if (!strcasecmp(folder, "Cust5")) {
02072 return 9;
02073 } else if (!strcasecmp(folder, "Urgent")) {
02074 return 11;
02075 } else {
02076 return 0;
02077 }
02078 }
02079
02080 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02081 {
02082 SEARCHPGM *pgm;
02083 SEARCHHEADER *hdr;
02084
02085 struct ast_vm_user *vmu, vmus;
02086 struct vm_state *vms_p;
02087 int ret = 0;
02088 int fold = folder_int(folder);
02089 int urgent = 0;
02090
02091
02092 if (fold == 11) {
02093 fold = NEW_FOLDER;
02094 urgent = 1;
02095 }
02096
02097 if (ast_strlen_zero(mailbox))
02098 return 0;
02099
02100
02101 vmu = find_user(&vmus, context, mailbox);
02102 if (!vmu) {
02103 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02104 return -1;
02105 } else {
02106
02107 if (vmu->imapuser[0] == '\0') {
02108 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02109 return -1;
02110 }
02111 }
02112
02113
02114 if (vmu->imapuser[0] == '\0') {
02115 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02116 free_user(vmu);
02117 return -1;
02118 }
02119 ast_assert(msgnum < vms->msg_array_max);
02120
02121
02122 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02123 if (!vms_p) {
02124 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02125 }
02126 if (vms_p) {
02127 ast_debug(3, "Returning before search - user is logged in\n");
02128 if (fold == 0) {
02129 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02130 }
02131 if (fold == 1) {
02132 return vms_p->oldmessages;
02133 }
02134 }
02135
02136
02137 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02138 if (!vms_p) {
02139 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02140 }
02141
02142 if (!vms_p) {
02143 vms_p = create_vm_state_from_user(vmu);
02144 }
02145 ret = init_mailstream(vms_p, fold);
02146 if (!vms_p->mailstream) {
02147 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02148 return -1;
02149 }
02150 if (ret == 0) {
02151 ast_mutex_lock(&vms_p->lock);
02152 pgm = mail_newsearchpgm ();
02153 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02154 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02155 pgm->header = hdr;
02156 if (fold != OLD_FOLDER) {
02157 pgm->unseen = 1;
02158 pgm->seen = 0;
02159 }
02160
02161
02162
02163 else {
02164 pgm->unseen = 0;
02165 pgm->seen = 1;
02166 }
02167
02168 if (fold == NEW_FOLDER) {
02169 if (urgent) {
02170 pgm->flagged = 1;
02171 pgm->unflagged = 0;
02172 } else {
02173 pgm->flagged = 0;
02174 pgm->unflagged = 1;
02175 }
02176 }
02177 pgm->undeleted = 1;
02178 pgm->deleted = 0;
02179
02180 vms_p->vmArrayIndex = 0;
02181 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02182 if (fold == 0 && urgent == 0)
02183 vms_p->newmessages = vms_p->vmArrayIndex;
02184 if (fold == 1)
02185 vms_p->oldmessages = vms_p->vmArrayIndex;
02186 if (fold == 0 && urgent == 1)
02187 vms_p->urgentmessages = vms_p->vmArrayIndex;
02188
02189 mail_free_searchpgm(&pgm);
02190 ast_mutex_unlock(&vms_p->lock);
02191 vms_p->updated = 0;
02192 return vms_p->vmArrayIndex;
02193 } else {
02194 ast_mutex_lock(&vms_p->lock);
02195 mail_ping(vms_p->mailstream);
02196 ast_mutex_unlock(&vms_p->lock);
02197 }
02198 return 0;
02199 }
02200
02201 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02202 {
02203
02204 check_quota(vms, vmu->imapfolder);
02205 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02206 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02207 ast_play_and_wait(chan, "vm-mailboxfull");
02208 return -1;
02209 }
02210
02211
02212 ast_debug(3, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0));
02213 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02214 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02215 ast_play_and_wait(chan, "vm-mailboxfull");
02216 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02217 return -1;
02218 }
02219
02220 return 0;
02221 }
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232 static int messagecount(const char *context, const char *mailbox, const char *folder)
02233 {
02234 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02235 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02236 } else {
02237 return __messagecount(context, mailbox, folder);
02238 }
02239 }
02240
02241 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag)
02242 {
02243 char *myserveremail = serveremail;
02244 char fn[PATH_MAX];
02245 char introfn[PATH_MAX];
02246 char mailbox[256];
02247 char *stringp;
02248 FILE *p = NULL;
02249 char tmp[80] = "/tmp/astmail-XXXXXX";
02250 long len;
02251 void *buf;
02252 int tempcopy = 0;
02253 STRING str;
02254 int ret;
02255 char *imap_flags = NIL;
02256 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02257 int box = NEW_FOLDER;
02258
02259
02260 if (msgnum < 0) {
02261 if(!imapgreetings) {
02262 return 0;
02263 } else {
02264 box = GREETINGS_FOLDER;
02265 }
02266 }
02267
02268 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02269 return -1;
02270 }
02271
02272
02273 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02274 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02275 imap_flags = "\\FLAGGED";
02276 }
02277
02278
02279 fmt = ast_strdupa(fmt);
02280 stringp = fmt;
02281 strsep(&stringp, "|");
02282
02283 if (!ast_strlen_zero(vmu->serveremail))
02284 myserveremail = vmu->serveremail;
02285
02286 if (msgnum > -1)
02287 make_file(fn, sizeof(fn), dir, msgnum);
02288 else
02289 ast_copy_string (fn, dir, sizeof(fn));
02290
02291 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02292 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02293 *introfn = '\0';
02294 }
02295
02296 if (ast_strlen_zero(vmu->email)) {
02297
02298
02299
02300
02301
02302 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02303 tempcopy = 1;
02304 }
02305
02306 if (!strcmp(fmt, "wav49"))
02307 fmt = "WAV";
02308 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02309
02310
02311
02312 if (!(p = vm_mkftemp(tmp))) {
02313 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02314 if (tempcopy)
02315 *(vmu->email) = '\0';
02316 return -1;
02317 }
02318
02319 if (msgnum < 0 && imapgreetings) {
02320 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02321 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02322 return -1;
02323 }
02324 imap_delete_old_greeting(fn, vms);
02325 }
02326
02327 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02328 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02329 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02330 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02331
02332 len = ftell(p);
02333 rewind(p);
02334 if (!(buf = ast_malloc(len + 1))) {
02335 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02336 fclose(p);
02337 if (tempcopy)
02338 *(vmu->email) = '\0';
02339 return -1;
02340 }
02341 if (fread(buf, len, 1, p) < len) {
02342 if (ferror(p)) {
02343 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02344 return -1;
02345 }
02346 }
02347 ((char *) buf)[len] = '\0';
02348 INIT(&str, mail_string, buf, len);
02349 ret = init_mailstream(vms, box);
02350 if (ret == 0) {
02351 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02352 ast_mutex_lock(&vms->lock);
02353 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02354 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02355 ast_mutex_unlock(&vms->lock);
02356 fclose(p);
02357 unlink(tmp);
02358 ast_free(buf);
02359 } else {
02360 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02361 fclose(p);
02362 unlink(tmp);
02363 ast_free(buf);
02364 return -1;
02365 }
02366 ast_debug(3, "%s stored\n", fn);
02367
02368 if (tempcopy)
02369 *(vmu->email) = '\0';
02370 inprocess_count(vmu->mailbox, vmu->context, -1);
02371 return 0;
02372
02373 }
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386
02387
02388 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02389 {
02390 char tmp[PATH_MAX] = "";
02391 char *mailboxnc;
02392 char *context;
02393 char *mb;
02394 char *cur;
02395 if (newmsgs)
02396 *newmsgs = 0;
02397 if (oldmsgs)
02398 *oldmsgs = 0;
02399 if (urgentmsgs)
02400 *urgentmsgs = 0;
02401
02402 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02403
02404 if (ast_strlen_zero(mailbox_context))
02405 return 0;
02406
02407 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02408 context = strchr(tmp, '@');
02409 if (strchr(mailbox_context, ',')) {
02410 int tmpnew, tmpold, tmpurgent;
02411 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02412 mb = tmp;
02413 while ((cur = strsep(&mb, ", "))) {
02414 if (!ast_strlen_zero(cur)) {
02415 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02416 return -1;
02417 else {
02418 if (newmsgs)
02419 *newmsgs += tmpnew;
02420 if (oldmsgs)
02421 *oldmsgs += tmpold;
02422 if (urgentmsgs)
02423 *urgentmsgs += tmpurgent;
02424 }
02425 }
02426 }
02427 return 0;
02428 }
02429 if (context) {
02430 *context = '\0';
02431 mailboxnc = tmp;
02432 context++;
02433 } else {
02434 context = "default";
02435 mailboxnc = (char *) mailbox_context;
02436 }
02437
02438 if (newmsgs) {
02439 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02440 if (!vmu) {
02441 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02442 return -1;
02443 }
02444 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02445 free_user(vmu);
02446 return -1;
02447 }
02448 free_user(vmu);
02449 }
02450 if (oldmsgs) {
02451 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02452 return -1;
02453 }
02454 }
02455 if (urgentmsgs) {
02456 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02457 return -1;
02458 }
02459 }
02460 return 0;
02461 }
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473 static int has_voicemail(const char *mailbox, const char *folder)
02474 {
02475 char tmp[256], *tmp2, *box, *context;
02476 ast_copy_string(tmp, mailbox, sizeof(tmp));
02477 tmp2 = tmp;
02478 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02479 while ((box = strsep(&tmp2, ",&"))) {
02480 if (!ast_strlen_zero(box)) {
02481 if (has_voicemail(box, folder)) {
02482 return 1;
02483 }
02484 }
02485 }
02486 }
02487 if ((context = strchr(tmp, '@'))) {
02488 *context++ = '\0';
02489 } else {
02490 context = "default";
02491 }
02492 return __messagecount(context, tmp, folder) ? 1 : 0;
02493 }
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509
02510 static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, char *flag)
02511 {
02512 struct vm_state *sendvms = NULL, *destvms = NULL;
02513 char messagestring[10];
02514 if (msgnum >= recip->maxmsg) {
02515 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02516 return -1;
02517 }
02518 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02519 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02520 return -1;
02521 }
02522 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02523 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02524 return -1;
02525 }
02526 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02527 ast_mutex_lock(&sendvms->lock);
02528 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02529 ast_mutex_unlock(&sendvms->lock);
02530 return 0;
02531 }
02532 ast_mutex_unlock(&sendvms->lock);
02533 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02534 return -1;
02535 }
02536
02537 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02538 {
02539 char tmp[256], *t = tmp;
02540 size_t left = sizeof(tmp);
02541
02542 if (box == OLD_FOLDER) {
02543 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02544 } else {
02545 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02546 }
02547
02548 if (box == NEW_FOLDER) {
02549 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02550 } else {
02551 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02552 }
02553
02554
02555 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02556
02557
02558 if (!ast_strlen_zero(authuser))
02559 ast_build_string(&t, &left, "/authuser=%s", authuser);
02560
02561
02562 if (!ast_strlen_zero(imapflags))
02563 ast_build_string(&t, &left, "/%s", imapflags);
02564
02565
02566 #if 1
02567 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02568 #else
02569 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02570 #endif
02571 if (box == NEW_FOLDER || box == OLD_FOLDER)
02572 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02573 else if (box == GREETINGS_FOLDER)
02574 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02575 else {
02576 if (!ast_strlen_zero(imapparentfolder)) {
02577
02578 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02579 } else {
02580 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02581 }
02582 }
02583 }
02584
02585 static int init_mailstream(struct vm_state *vms, int box)
02586 {
02587 MAILSTREAM *stream = NIL;
02588 long debug;
02589 char tmp[256];
02590
02591 if (!vms) {
02592 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02593 return -1;
02594 }
02595 if (option_debug > 2)
02596 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02597 if (vms->mailstream == NIL || !vms->mailstream) {
02598 if (option_debug)
02599 ast_log(LOG_DEBUG, "mailstream not set.\n");
02600 } else {
02601 stream = vms->mailstream;
02602 }
02603
02604 debug = NIL;
02605
02606 if (delimiter == '\0') {
02607 char *cp;
02608 #ifdef USE_SYSTEM_IMAP
02609 #include <imap/linkage.c>
02610 #elif defined(USE_SYSTEM_CCLIENT)
02611 #include <c-client/linkage.c>
02612 #else
02613 #include "linkage.c"
02614 #endif
02615
02616 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02617 ast_mutex_lock(&vms->lock);
02618 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02619 ast_mutex_unlock(&vms->lock);
02620 if (stream == NIL) {
02621 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02622 return -1;
02623 }
02624 get_mailbox_delimiter(stream);
02625
02626 for (cp = vms->imapfolder; *cp; cp++)
02627 if (*cp == '/')
02628 *cp = delimiter;
02629 }
02630
02631 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02632 if (option_debug > 2)
02633 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02634 ast_mutex_lock(&vms->lock);
02635 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02636 ast_mutex_unlock(&vms->lock);
02637 if (vms->mailstream == NIL) {
02638 return -1;
02639 } else {
02640 return 0;
02641 }
02642 }
02643
02644 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02645 {
02646 SEARCHPGM *pgm;
02647 SEARCHHEADER *hdr;
02648 int ret, urgent = 0;
02649
02650
02651 if (box == 11) {
02652 box = NEW_FOLDER;
02653 urgent = 1;
02654 }
02655
02656 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02657 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02658 vms->imapversion = vmu->imapversion;
02659 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02660
02661 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02662 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02663 return -1;
02664 }
02665
02666 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02667
02668
02669 if (box == 0) {
02670 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02671 check_quota(vms, (char *) mbox(vmu, box));
02672 }
02673
02674 ast_mutex_lock(&vms->lock);
02675 pgm = mail_newsearchpgm();
02676
02677
02678 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02679 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02680 pgm->header = hdr;
02681 pgm->deleted = 0;
02682 pgm->undeleted = 1;
02683
02684
02685 if (box == NEW_FOLDER && urgent == 1) {
02686 pgm->unseen = 1;
02687 pgm->seen = 0;
02688 pgm->flagged = 1;
02689 pgm->unflagged = 0;
02690 } else if (box == NEW_FOLDER && urgent == 0) {
02691 pgm->unseen = 1;
02692 pgm->seen = 0;
02693 pgm->flagged = 0;
02694 pgm->unflagged = 1;
02695 } else if (box == OLD_FOLDER) {
02696 pgm->seen = 1;
02697 pgm->unseen = 0;
02698 }
02699
02700 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02701
02702 vms->vmArrayIndex = 0;
02703 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02704 vms->lastmsg = vms->vmArrayIndex - 1;
02705 mail_free_searchpgm(&pgm);
02706
02707
02708
02709
02710 if (box == 0 && !vms->dh_arraysize) {
02711 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02712 }
02713 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02714 ast_mutex_unlock(&vms->lock);
02715 return -1;
02716 }
02717
02718 ast_mutex_unlock(&vms->lock);
02719 return 0;
02720 }
02721
02722 static void write_file(char *filename, char *buffer, unsigned long len)
02723 {
02724 FILE *output;
02725
02726 output = fopen (filename, "w");
02727 if (fwrite(buffer, len, 1, output) != 1) {
02728 if (ferror(output)) {
02729 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02730 }
02731 }
02732 fclose (output);
02733 }
02734
02735 static void update_messages_by_imapuser(const char *user, unsigned long number)
02736 {
02737 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02738
02739 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02740 return;
02741 }
02742
02743 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02744
02745
02746 if (vms->vmArrayIndex >= vms->msg_array_max) {
02747 long *new_mem = ast_realloc(vms->msgArray, 2 * vms->msg_array_max * sizeof(long));
02748 if (!new_mem) {
02749 return;
02750 }
02751 vms->msgArray = new_mem;
02752 vms->msg_array_max *= 2;
02753 }
02754
02755 vms->msgArray[vms->vmArrayIndex++] = number;
02756 }
02757
02758 void mm_searched(MAILSTREAM *stream, unsigned long number)
02759 {
02760 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02761
02762 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02763 return;
02764
02765 update_messages_by_imapuser(user, number);
02766 }
02767
02768 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02769 {
02770 struct ast_variable *var;
02771 struct ast_vm_user *vmu;
02772
02773 vmu = ast_calloc(1, sizeof *vmu);
02774 if (!vmu)
02775 return NULL;
02776
02777 populate_defaults(vmu);
02778 ast_set_flag(vmu, VM_ALLOCED);
02779
02780 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02781 if (var) {
02782 apply_options_full(vmu, var);
02783 ast_variables_destroy(var);
02784 return vmu;
02785 } else {
02786 ast_free(vmu);
02787 return NULL;
02788 }
02789 }
02790
02791
02792
02793 void mm_exists(MAILSTREAM * stream, unsigned long number)
02794 {
02795
02796 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02797 if (number == 0) return;
02798 set_update(stream);
02799 }
02800
02801
02802 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02803 {
02804
02805 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02806 if (number == 0) return;
02807 set_update(stream);
02808 }
02809
02810
02811 void mm_flags(MAILSTREAM * stream, unsigned long number)
02812 {
02813
02814 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02815 if (number == 0) return;
02816 set_update(stream);
02817 }
02818
02819
02820 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02821 {
02822 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02823 mm_log (string, errflg);
02824 }
02825
02826
02827 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02828 {
02829 if (delimiter == '\0') {
02830 delimiter = delim;
02831 }
02832
02833 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02834 if (attributes & LATT_NOINFERIORS)
02835 ast_debug(5, "no inferiors\n");
02836 if (attributes & LATT_NOSELECT)
02837 ast_debug(5, "no select\n");
02838 if (attributes & LATT_MARKED)
02839 ast_debug(5, "marked\n");
02840 if (attributes & LATT_UNMARKED)
02841 ast_debug(5, "unmarked\n");
02842 }
02843
02844
02845 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02846 {
02847 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02848 if (attributes & LATT_NOINFERIORS)
02849 ast_debug(5, "no inferiors\n");
02850 if (attributes & LATT_NOSELECT)
02851 ast_debug(5, "no select\n");
02852 if (attributes & LATT_MARKED)
02853 ast_debug(5, "marked\n");
02854 if (attributes & LATT_UNMARKED)
02855 ast_debug(5, "unmarked\n");
02856 }
02857
02858
02859 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02860 {
02861 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02862 if (status->flags & SA_MESSAGES)
02863 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02864 if (status->flags & SA_RECENT)
02865 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02866 if (status->flags & SA_UNSEEN)
02867 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02868 if (status->flags & SA_UIDVALIDITY)
02869 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02870 if (status->flags & SA_UIDNEXT)
02871 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02872 ast_log(AST_LOG_NOTICE, "\n");
02873 }
02874
02875
02876 void mm_log(char *string, long errflg)
02877 {
02878 switch ((short) errflg) {
02879 case NIL:
02880 ast_debug(1, "IMAP Info: %s\n", string);
02881 break;
02882 case PARSE:
02883 case WARN:
02884 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02885 break;
02886 case ERROR:
02887 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02888 break;
02889 }
02890 }
02891
02892
02893 void mm_dlog(char *string)
02894 {
02895 ast_log(AST_LOG_NOTICE, "%s\n", string);
02896 }
02897
02898
02899 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02900 {
02901 struct ast_vm_user *vmu;
02902
02903 ast_debug(4, "Entering callback mm_login\n");
02904
02905 ast_copy_string(user, mb->user, MAILTMPLEN);
02906
02907
02908 if (!ast_strlen_zero(authpassword)) {
02909 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02910 } else {
02911 AST_LIST_TRAVERSE(&users, vmu, list) {
02912 if (!strcasecmp(mb->user, vmu->imapuser)) {
02913 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02914 break;
02915 }
02916 }
02917 if (!vmu) {
02918 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02919 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02920 free_user(vmu);
02921 }
02922 }
02923 }
02924 }
02925
02926
02927 void mm_critical(MAILSTREAM * stream)
02928 {
02929 }
02930
02931
02932 void mm_nocritical(MAILSTREAM * stream)
02933 {
02934 }
02935
02936
02937 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02938 {
02939 kill (getpid (), SIGSTOP);
02940 return NIL;
02941 }
02942
02943
02944 void mm_fatal(char *string)
02945 {
02946 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02947 }
02948
02949
02950 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02951 {
02952 struct vm_state *vms;
02953 char *mailbox = stream->mailbox, *user;
02954 char buf[1024] = "";
02955 unsigned long usage = 0, limit = 0;
02956
02957 while (pquota) {
02958 usage = pquota->usage;
02959 limit = pquota->limit;
02960 pquota = pquota->next;
02961 }
02962
02963 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || (!(vms = get_vm_state_by_imapuser(user, 2)) && !(vms = get_vm_state_by_imapuser(user, 0)))) {
02964 ast_log(AST_LOG_ERROR, "No state found.\n");
02965 return;
02966 }
02967
02968 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02969
02970 vms->quota_usage = usage;
02971 vms->quota_limit = limit;
02972 }
02973
02974 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02975 {
02976 char *start, *eol_pnt;
02977 int taglen;
02978
02979 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02980 return NULL;
02981
02982 taglen = strlen(tag) + 1;
02983 if (taglen < 1)
02984 return NULL;
02985
02986 if (!(start = strstr(header, tag)))
02987 return NULL;
02988
02989
02990 memset(buf, 0, len);
02991
02992 ast_copy_string(buf, start+taglen, len);
02993 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02994 *eol_pnt = '\0';
02995 return buf;
02996 }
02997
02998 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02999 {
03000 char *start, *quote, *eol_pnt;
03001
03002 if (ast_strlen_zero(mailbox))
03003 return NULL;
03004
03005 if (!(start = strstr(mailbox, "/user=")))
03006 return NULL;
03007
03008 ast_copy_string(buf, start+6, len);
03009
03010 if (!(quote = strchr(buf, '\"'))) {
03011 if (!(eol_pnt = strchr(buf, '/')))
03012 eol_pnt = strchr(buf,'}');
03013 *eol_pnt = '\0';
03014 return buf;
03015 } else {
03016 eol_pnt = strchr(buf+1,'\"');
03017 *eol_pnt = '\0';
03018 return buf+1;
03019 }
03020 }
03021
03022 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
03023 {
03024 struct vm_state *vms_p;
03025
03026 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03027 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
03028 return vms_p;
03029 }
03030 if (option_debug > 4)
03031 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
03032
03033 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
03034 return NULL;
03035 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
03036 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
03037 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03038 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03039 vms_p->mailstream = NIL;
03040 vms_p->imapversion = vmu->imapversion;
03041 if (option_debug > 4)
03042 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03043 vms_p->updated = 1;
03044
03045 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03046 init_vm_state(vms_p);
03047 vmstate_insert(vms_p);
03048 return vms_p;
03049 }
03050
03051 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03052 {
03053 struct vmstate *vlist = NULL;
03054
03055 if (interactive) {
03056 struct vm_state *vms;
03057 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03058 vms = pthread_getspecific(ts_vmstate.key);
03059 return vms;
03060 }
03061
03062 AST_LIST_LOCK(&vmstates);
03063 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03064 if (!vlist->vms) {
03065 ast_debug(3, "error: vms is NULL for %s\n", user);
03066 continue;
03067 }
03068 if (vlist->vms->imapversion != imapversion) {
03069 continue;
03070 }
03071 if (!vlist->vms->imapuser) {
03072 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03073 continue;
03074 }
03075
03076 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03077 AST_LIST_UNLOCK(&vmstates);
03078 return vlist->vms;
03079 }
03080 }
03081 AST_LIST_UNLOCK(&vmstates);
03082
03083 ast_debug(3, "%s not found in vmstates\n", user);
03084
03085 return NULL;
03086 }
03087
03088 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03089 {
03090
03091 struct vmstate *vlist = NULL;
03092 const char *local_context = S_OR(context, "default");
03093
03094 if (interactive) {
03095 struct vm_state *vms;
03096 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03097 vms = pthread_getspecific(ts_vmstate.key);
03098 return vms;
03099 }
03100
03101 AST_LIST_LOCK(&vmstates);
03102 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03103 if (!vlist->vms) {
03104 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03105 continue;
03106 }
03107 if (vlist->vms->imapversion != imapversion) {
03108 continue;
03109 }
03110 if (!vlist->vms->username || !vlist->vms->context) {
03111 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03112 continue;
03113 }
03114
03115 ast_debug(3, "comparing mailbox %s@%s (i=%d) to vmstate mailbox %s@%s (i=%d)\n", mailbox, local_context, interactive, vlist->vms->username, vlist->vms->context, vlist->vms->interactive);
03116
03117 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03118 ast_debug(3, "Found it!\n");
03119 AST_LIST_UNLOCK(&vmstates);
03120 return vlist->vms;
03121 }
03122 }
03123 AST_LIST_UNLOCK(&vmstates);
03124
03125 ast_debug(3, "%s not found in vmstates\n", mailbox);
03126
03127 return NULL;
03128 }
03129
03130 static void vmstate_insert(struct vm_state *vms)
03131 {
03132 struct vmstate *v;
03133 struct vm_state *altvms;
03134
03135
03136
03137
03138 if (vms->interactive == 1) {
03139 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03140 if (altvms) {
03141 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03142 vms->newmessages = altvms->newmessages;
03143 vms->oldmessages = altvms->oldmessages;
03144 vms->vmArrayIndex = altvms->vmArrayIndex;
03145
03146 vms->lastmsg = altvms->lastmsg;
03147 vms->curmsg = altvms->curmsg;
03148
03149 vms->persist_vms = altvms;
03150
03151 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03152 vms->mailstream = altvms->mailstream;
03153 #else
03154 vms->mailstream = NIL;
03155 #endif
03156 }
03157 return;
03158 }
03159
03160 if (!(v = ast_calloc(1, sizeof(*v))))
03161 return;
03162
03163 v->vms = vms;
03164
03165 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03166
03167 AST_LIST_LOCK(&vmstates);
03168 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03169 AST_LIST_UNLOCK(&vmstates);
03170 }
03171
03172 static void vmstate_delete(struct vm_state *vms)
03173 {
03174 struct vmstate *vc = NULL;
03175 struct vm_state *altvms = NULL;
03176
03177
03178
03179 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03180 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03181 altvms->newmessages = vms->newmessages;
03182 altvms->oldmessages = vms->oldmessages;
03183 altvms->updated = 1;
03184 vms->mailstream = mail_close(vms->mailstream);
03185
03186
03187 return;
03188 }
03189
03190 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03191
03192 AST_LIST_LOCK(&vmstates);
03193 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03194 if (vc->vms == vms) {
03195 AST_LIST_REMOVE_CURRENT(list);
03196 break;
03197 }
03198 }
03199 AST_LIST_TRAVERSE_SAFE_END
03200 AST_LIST_UNLOCK(&vmstates);
03201
03202 if (vc) {
03203 ast_mutex_destroy(&vc->vms->lock);
03204 ast_free(vc->vms->msgArray);
03205 vc->vms->msgArray = NULL;
03206 vc->vms->msg_array_max = 0;
03207
03208 ast_free(vc);
03209 } else {
03210 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03211 }
03212 }
03213
03214 static void set_update(MAILSTREAM * stream)
03215 {
03216 struct vm_state *vms;
03217 char *mailbox = stream->mailbox, *user;
03218 char buf[1024] = "";
03219
03220 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03221 if (user && option_debug > 2)
03222 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03223 return;
03224 }
03225
03226 ast_debug(3, "User %s mailbox set for update.\n", user);
03227
03228 vms->updated = 1;
03229 }
03230
03231 static void init_vm_state(struct vm_state *vms)
03232 {
03233 vms->msg_array_max = VMSTATE_MAX_MSG_ARRAY;
03234 vms->msgArray = ast_calloc(vms->msg_array_max, sizeof(long));
03235 if (!vms->msgArray) {
03236
03237 vms->msg_array_max = 0;
03238 }
03239 vms->vmArrayIndex = 0;
03240 ast_mutex_init(&vms->lock);
03241 }
03242
03243 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03244 {
03245 char *body_content;
03246 char *body_decoded;
03247 char *fn = is_intro ? vms->introfn : vms->fn;
03248 unsigned long len;
03249 unsigned long newlen;
03250 char filename[256];
03251
03252 if (!body || body == NIL)
03253 return -1;
03254
03255 ast_mutex_lock(&vms->lock);
03256 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03257 ast_mutex_unlock(&vms->lock);
03258 if (body_content != NIL) {
03259 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03260
03261 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03262
03263 if (!newlen) {
03264 return -1;
03265 }
03266 write_file(filename, (char *) body_decoded, newlen);
03267 } else {
03268 ast_debug(5, "Body of message is NULL.\n");
03269 return -1;
03270 }
03271 return 0;
03272 }
03273
03274
03275
03276
03277
03278
03279
03280
03281 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03282 char tmp[50];
03283 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03284 mail_list(stream, tmp, "*");
03285 }
03286
03287
03288
03289
03290
03291
03292
03293
03294 static void check_quota(struct vm_state *vms, char *mailbox) {
03295 ast_mutex_lock(&vms->lock);
03296 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03297 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03298 if (vms && vms->mailstream != NULL) {
03299 imap_getquotaroot(vms->mailstream, mailbox);
03300 } else {
03301 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03302 }
03303 ast_mutex_unlock(&vms->lock);
03304 }
03305
03306 #endif
03307
03308
03309
03310
03311
03312 static int vm_lock_path(const char *path)
03313 {
03314 switch (ast_lock_path(path)) {
03315 case AST_LOCK_TIMEOUT:
03316 return -1;
03317 default:
03318 return 0;
03319 }
03320 }
03321
03322
03323 #ifdef ODBC_STORAGE
03324 struct generic_prepare_struct {
03325 char *sql;
03326 int argc;
03327 char **argv;
03328 };
03329
03330 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03331 {
03332 struct generic_prepare_struct *gps = data;
03333 int res, i;
03334 SQLHSTMT stmt;
03335
03336 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03337 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03338 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03339 return NULL;
03340 }
03341 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03342 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03343 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03344 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03345 return NULL;
03346 }
03347 for (i = 0; i < gps->argc; i++)
03348 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03349
03350 return stmt;
03351 }
03352
03353
03354
03355
03356
03357
03358
03359
03360
03361
03362
03363
03364
03365
03366
03367 static int retrieve_file(char *dir, int msgnum)
03368 {
03369 int x = 0;
03370 int res;
03371 int fd = -1;
03372 size_t fdlen = 0;
03373 void *fdm = MAP_FAILED;
03374 SQLSMALLINT colcount = 0;
03375 SQLHSTMT stmt;
03376 char sql[PATH_MAX];
03377 char fmt[80]="";
03378 char *c;
03379 char coltitle[256];
03380 SQLSMALLINT collen;
03381 SQLSMALLINT datatype;
03382 SQLSMALLINT decimaldigits;
03383 SQLSMALLINT nullable;
03384 SQLULEN colsize;
03385 SQLLEN colsize2;
03386 FILE *f = NULL;
03387 char rowdata[80];
03388 char fn[PATH_MAX];
03389 char full_fn[PATH_MAX];
03390 char msgnums[80];
03391 char *argv[] = { dir, msgnums };
03392 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03393
03394 struct odbc_obj *obj;
03395 obj = ast_odbc_request_obj(odbc_database, 0);
03396 if (obj) {
03397 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03398 c = strchr(fmt, '|');
03399 if (c)
03400 *c = '\0';
03401 if (!strcasecmp(fmt, "wav49"))
03402 strcpy(fmt, "WAV");
03403 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03404 if (msgnum > -1)
03405 make_file(fn, sizeof(fn), dir, msgnum);
03406 else
03407 ast_copy_string(fn, dir, sizeof(fn));
03408
03409
03410 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03411
03412 if (!(f = fopen(full_fn, "w+"))) {
03413 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03414 goto yuck;
03415 }
03416
03417 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03418 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03419 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03420 if (!stmt) {
03421 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03422 ast_odbc_release_obj(obj);
03423 goto yuck;
03424 }
03425 res = SQLFetch(stmt);
03426 if (res == SQL_NO_DATA) {
03427 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03428 ast_odbc_release_obj(obj);
03429 goto yuck;
03430 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03431 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03432 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03433 ast_odbc_release_obj(obj);
03434 goto yuck;
03435 }
03436 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03437 if (fd < 0) {
03438 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03439 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03440 ast_odbc_release_obj(obj);
03441 goto yuck;
03442 }
03443 res = SQLNumResultCols(stmt, &colcount);
03444 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03445 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03446 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03447 ast_odbc_release_obj(obj);
03448 goto yuck;
03449 }
03450 if (f)
03451 fprintf(f, "[message]\n");
03452 for (x = 0; x < colcount; x++) {
03453 rowdata[0] = '\0';
03454 colsize = 0;
03455 collen = sizeof(coltitle);
03456 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03457 &datatype, &colsize, &decimaldigits, &nullable);
03458 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03459 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03460 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03461 ast_odbc_release_obj(obj);
03462 goto yuck;
03463 }
03464 if (!strcasecmp(coltitle, "recording")) {
03465 off_t offset;
03466 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03467 fdlen = colsize2;
03468 if (fd > -1) {
03469 char tmp[1]="";
03470 lseek(fd, fdlen - 1, SEEK_SET);
03471 if (write(fd, tmp, 1) != 1) {
03472 close(fd);
03473 fd = -1;
03474 continue;
03475 }
03476
03477 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03478 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03479 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03480 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03481 ast_odbc_release_obj(obj);
03482 goto yuck;
03483 } else {
03484 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03485 munmap(fdm, CHUNKSIZE);
03486 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03487 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03488 unlink(full_fn);
03489 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03490 ast_odbc_release_obj(obj);
03491 goto yuck;
03492 }
03493 }
03494 }
03495 if (truncate(full_fn, fdlen) < 0) {
03496 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03497 }
03498 }
03499 } else {
03500 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03501 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03502 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03503 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03504 ast_odbc_release_obj(obj);
03505 goto yuck;
03506 }
03507 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03508 fprintf(f, "%s=%s\n", coltitle, rowdata);
03509 }
03510 }
03511 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03512 ast_odbc_release_obj(obj);
03513 } else
03514 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03515 yuck:
03516 if (f)
03517 fclose(f);
03518 if (fd > -1)
03519 close(fd);
03520 return x - 1;
03521 }
03522
03523
03524
03525
03526
03527
03528
03529
03530
03531
03532
03533
03534 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03535 {
03536 int x = 0;
03537 int res;
03538 SQLHSTMT stmt;
03539 char sql[PATH_MAX];
03540 char rowdata[20];
03541 char *argv[] = { dir };
03542 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03543
03544 struct odbc_obj *obj;
03545 obj = ast_odbc_request_obj(odbc_database, 0);
03546 if (obj) {
03547 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03548
03549 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03550 if (!stmt) {
03551 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03552 ast_odbc_release_obj(obj);
03553 goto yuck;
03554 }
03555 res = SQLFetch(stmt);
03556 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03557 if (res == SQL_NO_DATA) {
03558 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03559 } else {
03560 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03561 }
03562
03563 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03564 ast_odbc_release_obj(obj);
03565 goto yuck;
03566 }
03567 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03568 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03569 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03570 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03571 ast_odbc_release_obj(obj);
03572 goto yuck;
03573 }
03574 if (sscanf(rowdata, "%30d", &x) != 1)
03575 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03576 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03577 ast_odbc_release_obj(obj);
03578 return x;
03579 } else
03580 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03581 yuck:
03582 return x - 1;
03583 }
03584
03585
03586
03587
03588
03589
03590
03591
03592
03593
03594 static int message_exists(char *dir, int msgnum)
03595 {
03596 int x = 0;
03597 int res;
03598 SQLHSTMT stmt;
03599 char sql[PATH_MAX];
03600 char rowdata[20];
03601 char msgnums[20];
03602 char *argv[] = { dir, msgnums };
03603 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03604
03605 struct odbc_obj *obj;
03606 obj = ast_odbc_request_obj(odbc_database, 0);
03607 if (obj) {
03608 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03609 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03610 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03611 if (!stmt) {
03612 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03613 ast_odbc_release_obj(obj);
03614 goto yuck;
03615 }
03616 res = SQLFetch(stmt);
03617 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03618 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03619 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03620 ast_odbc_release_obj(obj);
03621 goto yuck;
03622 }
03623 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03624 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03625 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03626 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03627 ast_odbc_release_obj(obj);
03628 goto yuck;
03629 }
03630 if (sscanf(rowdata, "%30d", &x) != 1)
03631 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03632 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03633 ast_odbc_release_obj(obj);
03634 } else
03635 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03636 yuck:
03637 return x;
03638 }
03639
03640
03641
03642
03643
03644
03645
03646
03647
03648
03649 static int count_messages(struct ast_vm_user *vmu, char *dir)
03650 {
03651 int x = 0;
03652 int res;
03653 SQLHSTMT stmt;
03654 char sql[PATH_MAX];
03655 char rowdata[20];
03656 char *argv[] = { dir };
03657 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03658
03659 struct odbc_obj *obj;
03660 obj = ast_odbc_request_obj(odbc_database, 0);
03661 if (obj) {
03662 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03663 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03664 if (!stmt) {
03665 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03666 ast_odbc_release_obj(obj);
03667 goto yuck;
03668 }
03669 res = SQLFetch(stmt);
03670 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03671 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03672 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03673 ast_odbc_release_obj(obj);
03674 goto yuck;
03675 }
03676 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03677 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03678 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03679 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03680 ast_odbc_release_obj(obj);
03681 goto yuck;
03682 }
03683 if (sscanf(rowdata, "%30d", &x) != 1)
03684 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03685 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03686 ast_odbc_release_obj(obj);
03687 return x;
03688 } else
03689 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03690 yuck:
03691 return x - 1;
03692
03693 }
03694
03695
03696
03697
03698
03699
03700
03701
03702
03703
03704
03705 static void delete_file(const char *sdir, int smsg)
03706 {
03707 SQLHSTMT stmt;
03708 char sql[PATH_MAX];
03709 char msgnums[20];
03710 char *argv[] = { NULL, msgnums };
03711 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03712 struct odbc_obj *obj;
03713
03714 argv[0] = ast_strdupa(sdir);
03715
03716 obj = ast_odbc_request_obj(odbc_database, 0);
03717 if (obj) {
03718 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03719 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03720 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03721 if (!stmt)
03722 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03723 else
03724 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03725 ast_odbc_release_obj(obj);
03726 } else
03727 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03728 return;
03729 }
03730
03731
03732
03733
03734
03735
03736
03737
03738
03739
03740
03741
03742 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03743 {
03744 SQLHSTMT stmt;
03745 char sql[512];
03746 char msgnums[20];
03747 char msgnumd[20];
03748 struct odbc_obj *obj;
03749 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03750 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03751
03752 delete_file(ddir, dmsg);
03753 obj = ast_odbc_request_obj(odbc_database, 0);
03754 if (obj) {
03755 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03756 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03757 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table);
03758 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03759 if (!stmt)
03760 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03761 else
03762 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03763 ast_odbc_release_obj(obj);
03764 } else
03765 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03766 return;
03767 }
03768
03769 struct insert_data {
03770 char *sql;
03771 const char *dir;
03772 const char *msgnums;
03773 void *data;
03774 SQLLEN datalen;
03775 SQLLEN indlen;
03776 const char *context;
03777 const char *macrocontext;
03778 const char *callerid;
03779 const char *origtime;
03780 const char *duration;
03781 const char *mailboxuser;
03782 const char *mailboxcontext;
03783 const char *category;
03784 const char *flag;
03785 };
03786
03787 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03788 {
03789 struct insert_data *data = vdata;
03790 int res;
03791 SQLHSTMT stmt;
03792
03793 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03794 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03795 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03796 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03797 return NULL;
03798 }
03799
03800 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03801 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03802 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03803 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03804 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03805 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03806 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03807 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03808 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03809 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03810 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03811 if (!ast_strlen_zero(data->category)) {
03812 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03813 }
03814 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03815 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03816 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03817 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03818 return NULL;
03819 }
03820
03821 return stmt;
03822 }
03823
03824
03825
03826
03827
03828
03829
03830
03831
03832
03833
03834
03835
03836
03837 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03838 {
03839 int res = 0;
03840 int fd = -1;
03841 void *fdm = MAP_FAILED;
03842 off_t fdlen = -1;
03843 SQLHSTMT stmt;
03844 char sql[PATH_MAX];
03845 char msgnums[20];
03846 char fn[PATH_MAX];
03847 char full_fn[PATH_MAX];
03848 char fmt[80]="";
03849 char *c;
03850 struct ast_config *cfg = NULL;
03851 struct odbc_obj *obj;
03852 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03853 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03854 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03855
03856 delete_file(dir, msgnum);
03857 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03858 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03859 return -1;
03860 }
03861
03862 do {
03863 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03864 c = strchr(fmt, '|');
03865 if (c)
03866 *c = '\0';
03867 if (!strcasecmp(fmt, "wav49"))
03868 strcpy(fmt, "WAV");
03869 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03870 if (msgnum > -1)
03871 make_file(fn, sizeof(fn), dir, msgnum);
03872 else
03873 ast_copy_string(fn, dir, sizeof(fn));
03874 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03875 cfg = ast_config_load(full_fn, config_flags);
03876 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03877 fd = open(full_fn, O_RDWR);
03878 if (fd < 0) {
03879 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03880 res = -1;
03881 break;
03882 }
03883 if (valid_config(cfg)) {
03884 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03885 idata.context = "";
03886 }
03887 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03888 idata.macrocontext = "";
03889 }
03890 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03891 idata.callerid = "";
03892 }
03893 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03894 idata.origtime = "";
03895 }
03896 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03897 idata.duration = "";
03898 }
03899 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03900 idata.category = "";
03901 }
03902 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03903 idata.flag = "";
03904 }
03905 }
03906 fdlen = lseek(fd, 0, SEEK_END);
03907 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03908 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03909 res = -1;
03910 break;
03911 }
03912 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03913 if (fdm == MAP_FAILED) {
03914 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03915 res = -1;
03916 break;
03917 }
03918 idata.data = fdm;
03919 idata.datalen = idata.indlen = fdlen;
03920
03921 if (!ast_strlen_zero(idata.category))
03922 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03923 else
03924 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03925
03926 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03927 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03928 } else {
03929 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03930 res = -1;
03931 }
03932 } while (0);
03933 if (obj) {
03934 ast_odbc_release_obj(obj);
03935 }
03936 if (valid_config(cfg))
03937 ast_config_destroy(cfg);
03938 if (fdm != MAP_FAILED)
03939 munmap(fdm, fdlen);
03940 if (fd > -1)
03941 close(fd);
03942 return res;
03943 }
03944
03945
03946
03947
03948
03949
03950
03951
03952
03953
03954
03955
03956
03957
03958 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03959 {
03960 SQLHSTMT stmt;
03961 char sql[PATH_MAX];
03962 char msgnums[20];
03963 char msgnumd[20];
03964 struct odbc_obj *obj;
03965 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03966 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03967
03968 delete_file(ddir, dmsg);
03969 obj = ast_odbc_request_obj(odbc_database, 0);
03970 if (obj) {
03971 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03972 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03973 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03974 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03975 if (!stmt)
03976 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03977 else
03978 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03979 ast_odbc_release_obj(obj);
03980 } else
03981 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03982 return;
03983 }
03984
03985
03986
03987
03988
03989
03990
03991
03992
03993
03994
03995
03996 static int remove_file(char *dir, int msgnum)
03997 {
03998 char fn[PATH_MAX];
03999 char full_fn[PATH_MAX];
04000 char msgnums[80];
04001
04002 if (msgnum > -1) {
04003 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
04004 make_file(fn, sizeof(fn), dir, msgnum);
04005 } else
04006 ast_copy_string(fn, dir, sizeof(fn));
04007 ast_filedelete(fn, NULL);
04008 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
04009 unlink(full_fn);
04010 return 0;
04011 }
04012 #else
04013 #ifndef IMAP_STORAGE
04014
04015
04016
04017
04018
04019
04020
04021
04022
04023 static int count_messages(struct ast_vm_user *vmu, char *dir)
04024 {
04025
04026 int vmcount = 0;
04027 DIR *vmdir = NULL;
04028 struct dirent *vment = NULL;
04029
04030 if (vm_lock_path(dir))
04031 return ERROR_LOCK_PATH;
04032
04033 if ((vmdir = opendir(dir))) {
04034 while ((vment = readdir(vmdir))) {
04035 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
04036 vmcount++;
04037 }
04038 }
04039 closedir(vmdir);
04040 }
04041 ast_unlock_path(dir);
04042
04043 return vmcount;
04044 }
04045
04046
04047
04048
04049
04050
04051
04052
04053 static void rename_file(char *sfn, char *dfn)
04054 {
04055 char stxt[PATH_MAX];
04056 char dtxt[PATH_MAX];
04057 ast_filerename(sfn, dfn, NULL);
04058 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04059 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04060 if (ast_check_realtime("voicemail_data")) {
04061 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04062 }
04063 rename(stxt, dtxt);
04064 }
04065
04066
04067
04068
04069
04070
04071
04072
04073
04074
04075
04076
04077 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04078 {
04079 int x;
04080 unsigned char map[MAXMSGLIMIT] = "";
04081 DIR *msgdir;
04082 struct dirent *msgdirent;
04083 int msgdirint;
04084 char extension[4];
04085 int stopcount = 0;
04086
04087
04088
04089
04090
04091 if (!(msgdir = opendir(dir))) {
04092 return -1;
04093 }
04094
04095 while ((msgdirent = readdir(msgdir))) {
04096 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04097 map[msgdirint] = 1;
04098 stopcount++;
04099 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04100 }
04101 }
04102 closedir(msgdir);
04103
04104 for (x = 0; x < vmu->maxmsg; x++) {
04105 if (map[x] == 1) {
04106 stopcount--;
04107 } else if (map[x] == 0 && !stopcount) {
04108 break;
04109 }
04110 }
04111
04112 return x - 1;
04113 }
04114
04115 #endif
04116 #endif
04117 #ifndef IMAP_STORAGE
04118
04119
04120
04121
04122
04123
04124
04125
04126
04127
04128 static int copy(char *infile, char *outfile)
04129 {
04130 int ifd;
04131 int ofd;
04132 int res;
04133 int len;
04134 char buf[4096];
04135
04136 #ifdef HARDLINK_WHEN_POSSIBLE
04137
04138 if (link(infile, outfile)) {
04139 #endif
04140 if ((ifd = open(infile, O_RDONLY)) < 0) {
04141 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04142 return -1;
04143 }
04144 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04145 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04146 close(ifd);
04147 return -1;
04148 }
04149 do {
04150 len = read(ifd, buf, sizeof(buf));
04151 if (len < 0) {
04152 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04153 close(ifd);
04154 close(ofd);
04155 unlink(outfile);
04156 } else if (len) {
04157 res = write(ofd, buf, len);
04158 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04159 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04160 close(ifd);
04161 close(ofd);
04162 unlink(outfile);
04163 }
04164 }
04165 } while (len);
04166 close(ifd);
04167 close(ofd);
04168 return 0;
04169 #ifdef HARDLINK_WHEN_POSSIBLE
04170 } else {
04171
04172 return 0;
04173 }
04174 #endif
04175 }
04176
04177
04178
04179
04180
04181
04182
04183
04184
04185
04186 static void copy_plain_file(char *frompath, char *topath)
04187 {
04188 char frompath2[PATH_MAX], topath2[PATH_MAX];
04189 struct ast_variable *tmp,*var = NULL;
04190 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04191 ast_filecopy(frompath, topath, NULL);
04192 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04193 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04194 if (ast_check_realtime("voicemail_data")) {
04195 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04196
04197 for (tmp = var; tmp; tmp = tmp->next) {
04198 if (!strcasecmp(tmp->name, "origmailbox")) {
04199 origmailbox = tmp->value;
04200 } else if (!strcasecmp(tmp->name, "context")) {
04201 context = tmp->value;
04202 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04203 macrocontext = tmp->value;
04204 } else if (!strcasecmp(tmp->name, "exten")) {
04205 exten = tmp->value;
04206 } else if (!strcasecmp(tmp->name, "priority")) {
04207 priority = tmp->value;
04208 } else if (!strcasecmp(tmp->name, "callerchan")) {
04209 callerchan = tmp->value;
04210 } else if (!strcasecmp(tmp->name, "callerid")) {
04211 callerid = tmp->value;
04212 } else if (!strcasecmp(tmp->name, "origdate")) {
04213 origdate = tmp->value;
04214 } else if (!strcasecmp(tmp->name, "origtime")) {
04215 origtime = tmp->value;
04216 } else if (!strcasecmp(tmp->name, "category")) {
04217 category = tmp->value;
04218 } else if (!strcasecmp(tmp->name, "duration")) {
04219 duration = tmp->value;
04220 }
04221 }
04222 ast_store_realtime("voicemail_data", "filename", topath, "origmailbox", origmailbox, "context", context, "macrocontext", macrocontext, "exten", exten, "priority", priority, "callerchan", callerchan, "callerid", callerid, "origdate", origdate, "origtime", origtime, "category", category, "duration", duration, SENTINEL);
04223 }
04224 copy(frompath2, topath2);
04225 ast_variables_destroy(var);
04226 }
04227 #endif
04228
04229
04230
04231
04232
04233
04234
04235
04236
04237 static int vm_delete(char *file)
04238 {
04239 char *txt;
04240 int txtsize = 0;
04241
04242 txtsize = (strlen(file) + 5)*sizeof(char);
04243 txt = ast_alloca(txtsize);
04244
04245
04246
04247 if (ast_check_realtime("voicemail_data")) {
04248 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04249 }
04250 snprintf(txt, txtsize, "%s.txt", file);
04251 unlink(txt);
04252 return ast_filedelete(file, NULL);
04253 }
04254
04255
04256
04257
04258 static int inbuf(struct baseio *bio, FILE *fi)
04259 {
04260 int l;
04261
04262 if (bio->ateof)
04263 return 0;
04264
04265 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04266 if (ferror(fi))
04267 return -1;
04268
04269 bio->ateof = 1;
04270 return 0;
04271 }
04272
04273 bio->iolen = l;
04274 bio->iocp = 0;
04275
04276 return 1;
04277 }
04278
04279
04280
04281
04282 static int inchar(struct baseio *bio, FILE *fi)
04283 {
04284 if (bio->iocp>=bio->iolen) {
04285 if (!inbuf(bio, fi))
04286 return EOF;
04287 }
04288
04289 return bio->iobuf[bio->iocp++];
04290 }
04291
04292
04293
04294
04295 static int ochar(struct baseio *bio, int c, FILE *so)
04296 {
04297 if (bio->linelength >= BASELINELEN) {
04298 if (fputs(ENDL, so) == EOF) {
04299 return -1;
04300 }
04301
04302 bio->linelength = 0;
04303 }
04304
04305 if (putc(((unsigned char) c), so) == EOF) {
04306 return -1;
04307 }
04308
04309 bio->linelength++;
04310
04311 return 1;
04312 }
04313
04314
04315
04316
04317
04318
04319
04320
04321
04322
04323 static int base_encode(char *filename, FILE *so)
04324 {
04325 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04326 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04327 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04328 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04329 int i, hiteof = 0;
04330 FILE *fi;
04331 struct baseio bio;
04332
04333 memset(&bio, 0, sizeof(bio));
04334 bio.iocp = BASEMAXINLINE;
04335
04336 if (!(fi = fopen(filename, "rb"))) {
04337 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04338 return -1;
04339 }
04340
04341 while (!hiteof){
04342 unsigned char igroup[3], ogroup[4];
04343 int c, n;
04344
04345 memset(igroup, 0, sizeof(igroup));
04346
04347 for (n = 0; n < 3; n++) {
04348 if ((c = inchar(&bio, fi)) == EOF) {
04349 hiteof = 1;
04350 break;
04351 }
04352
04353 igroup[n] = (unsigned char) c;
04354 }
04355
04356 if (n > 0) {
04357 ogroup[0]= dtable[igroup[0] >> 2];
04358 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04359 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04360 ogroup[3]= dtable[igroup[2] & 0x3F];
04361
04362 if (n < 3) {
04363 ogroup[3] = '=';
04364
04365 if (n < 2)
04366 ogroup[2] = '=';
04367 }
04368
04369 for (i = 0; i < 4; i++)
04370 ochar(&bio, ogroup[i], so);
04371 }
04372 }
04373
04374 fclose(fi);
04375
04376 if (fputs(ENDL, so) == EOF) {
04377 return 0;
04378 }
04379
04380 return 1;
04381 }
04382
04383 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, const char *category, const char *flag)
04384 {
04385 char callerid[256];
04386 char num[12];
04387 char fromdir[256], fromfile[256];
04388 struct ast_config *msg_cfg;
04389 const char *origcallerid, *origtime;
04390 char origcidname[80], origcidnum[80], origdate[80];
04391 int inttime;
04392 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04393
04394
04395 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04396 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04397 snprintf(num, sizeof(num), "%d", msgnum);
04398 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04399 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04400 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04401 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04402 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04403 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04404 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04405 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04406 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04407 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04408
04409
04410 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04411 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04412 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04413 strcat(fromfile, ".txt");
04414 }
04415 if (!(msg_cfg = ast_config_load(fromfile, config_flags)) || !(valid_config(msg_cfg))) {
04416 if (option_debug > 0) {
04417 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04418 }
04419 return;
04420 }
04421
04422 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04423 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04424 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04425 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04426 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04427 }
04428
04429 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04430 struct timeval tv = { inttime, };
04431 struct ast_tm tm;
04432 ast_localtime(&tv, &tm, NULL);
04433 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04434 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04435 }
04436 ast_config_destroy(msg_cfg);
04437 }
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04448 {
04449 const char *ptr;
04450
04451
04452 ast_str_set(buf, maxlen, "\"");
04453 for (ptr = from; *ptr; ptr++) {
04454 if (*ptr == '"' || *ptr == '\\') {
04455 ast_str_append(buf, maxlen, "\\%c", *ptr);
04456 } else {
04457 ast_str_append(buf, maxlen, "%c", *ptr);
04458 }
04459 }
04460 ast_str_append(buf, maxlen, "\"");
04461
04462 return ast_str_buffer(*buf);
04463 }
04464
04465
04466
04467
04468
04469 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04470 {
04471 const struct vm_zone *z = NULL;
04472 struct timeval t = ast_tvnow();
04473
04474
04475 if (!ast_strlen_zero(vmu->zonetag)) {
04476
04477 AST_LIST_LOCK(&zones);
04478 AST_LIST_TRAVERSE(&zones, z, list) {
04479 if (!strcmp(z->name, vmu->zonetag))
04480 break;
04481 }
04482 AST_LIST_UNLOCK(&zones);
04483 }
04484 ast_localtime(&t, tm, z ? z->timezone : NULL);
04485 return tm;
04486 }
04487
04488
04489
04490
04491
04492 static int check_mime(const char *str)
04493 {
04494 for (; *str; str++) {
04495 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04496 return 1;
04497 }
04498 }
04499 return 0;
04500 }
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518
04519 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04520 {
04521 struct ast_str *tmp = ast_str_alloca(80);
04522 int first_section = 1;
04523
04524 ast_str_reset(*end);
04525 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04526 for (; *start; start++) {
04527 int need_encoding = 0;
04528 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04529 need_encoding = 1;
04530 }
04531 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04532 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04533 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04534 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04535
04536 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04537 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04538 first_section = 0;
04539 }
04540 if (need_encoding && *start == ' ') {
04541 ast_str_append(&tmp, -1, "_");
04542 } else if (need_encoding) {
04543 ast_str_append(&tmp, -1, "=%hhX", *start);
04544 } else {
04545 ast_str_append(&tmp, -1, "%c", *start);
04546 }
04547 }
04548 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04549 return ast_str_buffer(*end);
04550 }
04551
04552
04553
04554
04555
04556
04557
04558
04559
04560
04561
04562
04563
04564
04565
04566
04567
04568
04569
04570
04571
04572
04573
04574
04575 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag)
04576 {
04577 char date[256];
04578 char host[MAXHOSTNAMELEN] = "";
04579 char who[256];
04580 char bound[256];
04581 char dur[256];
04582 struct ast_tm tm;
04583 char enc_cidnum[256] = "", enc_cidname[256] = "";
04584 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04585 char *greeting_attachment;
04586 char filename[256];
04587
04588 if (!str1 || !str2) {
04589 ast_free(str1);
04590 ast_free(str2);
04591 return;
04592 }
04593
04594 if (cidnum) {
04595 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04596 }
04597 if (cidname) {
04598 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04599 }
04600 gethostname(host, sizeof(host) - 1);
04601
04602 if (strchr(srcemail, '@')) {
04603 ast_copy_string(who, srcemail, sizeof(who));
04604 } else {
04605 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04606 }
04607
04608 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04609 if (greeting_attachment) {
04610 *greeting_attachment++ = '\0';
04611 }
04612
04613 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04614 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04615 fprintf(p, "Date: %s" ENDL, date);
04616
04617
04618 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04619
04620 if (!ast_strlen_zero(fromstring)) {
04621 struct ast_channel *ast;
04622 if ((ast = ast_dummy_channel_alloc())) {
04623 char *ptr;
04624 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04625 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04626
04627 if (check_mime(ast_str_buffer(str1))) {
04628 int first_line = 1;
04629 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04630 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04631 *ptr = '\0';
04632 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04633 first_line = 0;
04634
04635 ast_str_set(&str2, 0, "%s", ptr + 1);
04636 }
04637 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04638 } else {
04639 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04640 }
04641 ast = ast_channel_unref(ast);
04642 } else {
04643 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04644 }
04645 } else {
04646 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04647 }
04648
04649 if (check_mime(vmu->fullname)) {
04650 int first_line = 1;
04651 char *ptr;
04652 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04653 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04654 *ptr = '\0';
04655 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04656 first_line = 0;
04657
04658 ast_str_set(&str2, 0, "%s", ptr + 1);
04659 }
04660 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04661 } else {
04662 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04663 }
04664
04665 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04666 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04667 struct ast_channel *ast;
04668 if ((ast = ast_dummy_channel_alloc())) {
04669 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04670 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04671 if (check_mime(ast_str_buffer(str1))) {
04672 int first_line = 1;
04673 char *ptr;
04674 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04675 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04676 *ptr = '\0';
04677 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04678 first_line = 0;
04679
04680 ast_str_set(&str2, 0, "%s", ptr + 1);
04681 }
04682 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04683 } else {
04684 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04685 }
04686 ast = ast_channel_unref(ast);
04687 } else {
04688 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04689 }
04690 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04691 if (ast_strlen_zero(flag)) {
04692 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04693 } else {
04694 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04695 }
04696 } else {
04697 if (ast_strlen_zero(flag)) {
04698 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04699 } else {
04700 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04701 }
04702 }
04703
04704 fprintf(p, "Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
04705 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04706 if (imap) {
04707
04708 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04709
04710 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04711 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04712 #ifdef IMAP_STORAGE
04713 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04714 #else
04715 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04716 #endif
04717
04718 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04719 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04720 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04721 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04722 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04723 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04724 if (!ast_strlen_zero(category)) {
04725 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04726 } else {
04727 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04728 }
04729 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04730 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04731 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04732 }
04733 if (!ast_strlen_zero(cidnum)) {
04734 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04735 }
04736 if (!ast_strlen_zero(cidname)) {
04737 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04738 }
04739 fprintf(p, "MIME-Version: 1.0" ENDL);
04740 if (attach_user_voicemail) {
04741
04742 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%u", msgnum + 1, mailbox,
04743 (int) getpid(), (unsigned int) ast_random());
04744
04745 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04746 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04747 fprintf(p, "--%s" ENDL, bound);
04748 }
04749 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04750 if (emailbody || vmu->emailbody) {
04751 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04752 struct ast_channel *ast;
04753 if ((ast = ast_dummy_channel_alloc())) {
04754 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04755 ast_str_substitute_variables(&str1, 0, ast, e_body);
04756 #ifdef IMAP_STORAGE
04757 {
04758
04759 char *line = ast_str_buffer(str1), *next;
04760 do {
04761
04762 if ((next = strchr(line, '\n'))) {
04763 *next++ = '\0';
04764 }
04765 fprintf(p, "%s" ENDL, line);
04766 line = next;
04767 } while (!ast_strlen_zero(line));
04768 }
04769 #else
04770 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04771 #endif
04772 ast = ast_channel_unref(ast);
04773 } else {
04774 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04775 }
04776 } else if (msgnum > -1) {
04777 if (strcmp(vmu->mailbox, mailbox)) {
04778
04779 struct ast_config *msg_cfg;
04780 const char *v;
04781 int inttime;
04782 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04783 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04784
04785 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04786 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04787 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04788 strcat(fromfile, ".txt");
04789 }
04790 if ((msg_cfg = ast_config_load(fromfile, config_flags)) && valid_config(msg_cfg)) {
04791 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04792 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04793 }
04794
04795
04796
04797 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04798 struct timeval tv = { inttime, };
04799 struct ast_tm tm;
04800 ast_localtime(&tv, &tm, NULL);
04801 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04802 }
04803 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04804 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04805 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04806 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04807 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04808 date, origcallerid, origdate);
04809 ast_config_destroy(msg_cfg);
04810 } else {
04811 goto plain_message;
04812 }
04813 } else {
04814 plain_message:
04815 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04816 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04817 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04818 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04819 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04820 }
04821 } else {
04822 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04823 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04824 }
04825
04826 if (imap || attach_user_voicemail) {
04827 if (!ast_strlen_zero(attach2)) {
04828 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04829 ast_debug(5, "creating second attachment filename %s\n", filename);
04830 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04831 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04832 ast_debug(5, "creating attachment filename %s\n", filename);
04833 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04834 } else {
04835 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04836 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04837 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04838 }
04839 }
04840 ast_free(str1);
04841 ast_free(str2);
04842 }
04843
04844 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum)
04845 {
04846 char tmpdir[256], newtmp[256];
04847 char fname[256];
04848 char tmpcmd[256];
04849 int tmpfd = -1;
04850 int soxstatus = 0;
04851
04852
04853 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04854
04855 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04856 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04857 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04858 tmpfd = mkstemp(newtmp);
04859 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04860 ast_debug(3, "newtmp: %s\n", newtmp);
04861 if (tmpfd > -1) {
04862 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04863 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04864 attach = newtmp;
04865 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04866 } else {
04867 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04868 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04869 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04870 }
04871 }
04872 }
04873 fprintf(p, "--%s" ENDL, bound);
04874 if (msgnum > -1)
04875 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04876 else
04877 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04878 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04879 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04880 if (msgnum > -1)
04881 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04882 else
04883 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04884 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04885 base_encode(fname, p);
04886 if (last)
04887 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04888 if (tmpfd > -1) {
04889 if (soxstatus == 0) {
04890 unlink(fname);
04891 }
04892 close(tmpfd);
04893 unlink(newtmp);
04894 }
04895 return 0;
04896 }
04897
04898 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag)
04899 {
04900 FILE *p = NULL;
04901 char tmp[80] = "/tmp/astmail-XXXXXX";
04902 char tmp2[256];
04903 char *stringp;
04904
04905 if (vmu && ast_strlen_zero(vmu->email)) {
04906 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04907 return(0);
04908 }
04909
04910
04911 format = ast_strdupa(format);
04912 stringp = format;
04913 strsep(&stringp, "|");
04914
04915 if (!strcmp(format, "wav49"))
04916 format = "WAV";
04917 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %u\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04918
04919
04920 if ((p = vm_mkftemp(tmp)) == NULL) {
04921 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04922 return -1;
04923 } else {
04924 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04925 fclose(p);
04926 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04927 ast_safe_system(tmp2);
04928 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04929 }
04930 return 0;
04931 }
04932
04933 static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
04934 {
04935 char enc_cidnum[256], enc_cidname[256];
04936 char date[256];
04937 char host[MAXHOSTNAMELEN] = "";
04938 char who[256];
04939 char dur[PATH_MAX];
04940 char tmp[80] = "/tmp/astmail-XXXXXX";
04941 char tmp2[PATH_MAX];
04942 struct ast_tm tm;
04943 FILE *p;
04944 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04945
04946 if (!str1 || !str2) {
04947 ast_free(str1);
04948 ast_free(str2);
04949 return -1;
04950 }
04951
04952 if (cidnum) {
04953 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04954 }
04955 if (cidname) {
04956 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04957 }
04958
04959 if ((p = vm_mkftemp(tmp)) == NULL) {
04960 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04961 ast_free(str1);
04962 ast_free(str2);
04963 return -1;
04964 }
04965 gethostname(host, sizeof(host)-1);
04966 if (strchr(srcemail, '@')) {
04967 ast_copy_string(who, srcemail, sizeof(who));
04968 } else {
04969 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04970 }
04971 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04972 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04973 fprintf(p, "Date: %s\n", date);
04974
04975
04976 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04977
04978 if (!ast_strlen_zero(pagerfromstring)) {
04979 struct ast_channel *ast;
04980 if ((ast = ast_dummy_channel_alloc())) {
04981 char *ptr;
04982 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04983 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04984
04985 if (check_mime(ast_str_buffer(str1))) {
04986 int first_line = 1;
04987 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04988 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04989 *ptr = '\0';
04990 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04991 first_line = 0;
04992
04993 ast_str_set(&str2, 0, "%s", ptr + 1);
04994 }
04995 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04996 } else {
04997 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04998 }
04999 ast = ast_channel_unref(ast);
05000 } else {
05001 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05002 }
05003 } else {
05004 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
05005 }
05006
05007 if (check_mime(vmu->fullname)) {
05008 int first_line = 1;
05009 char *ptr;
05010 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
05011 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05012 *ptr = '\0';
05013 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
05014 first_line = 0;
05015
05016 ast_str_set(&str2, 0, "%s", ptr + 1);
05017 }
05018 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
05019 } else {
05020 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
05021 }
05022
05023 if (!ast_strlen_zero(pagersubject)) {
05024 struct ast_channel *ast;
05025 if ((ast = ast_dummy_channel_alloc())) {
05026 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05027 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
05028 if (check_mime(ast_str_buffer(str1))) {
05029 int first_line = 1;
05030 char *ptr;
05031 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
05032 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05033 *ptr = '\0';
05034 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05035 first_line = 0;
05036
05037 ast_str_set(&str2, 0, "%s", ptr + 1);
05038 }
05039 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05040 } else {
05041 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
05042 }
05043 ast = ast_channel_unref(ast);
05044 } else {
05045 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05046 }
05047 } else {
05048 if (ast_strlen_zero(flag)) {
05049 fprintf(p, "Subject: New VM\n\n");
05050 } else {
05051 fprintf(p, "Subject: New %s VM\n\n", flag);
05052 }
05053 }
05054
05055 if (pagerbody) {
05056 struct ast_channel *ast;
05057 if ((ast = ast_dummy_channel_alloc())) {
05058 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05059 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05060 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05061 ast = ast_channel_unref(ast);
05062 } else {
05063 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05064 }
05065 } else {
05066 fprintf(p, "New %s long %s msg in box %s\n"
05067 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05068 }
05069
05070 fclose(p);
05071 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05072 ast_safe_system(tmp2);
05073 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05074 ast_free(str1);
05075 ast_free(str2);
05076 return 0;
05077 }
05078
05079
05080
05081
05082
05083
05084
05085
05086
05087
05088 static int get_date(char *s, int len)
05089 {
05090 struct ast_tm tm;
05091 struct timeval t = ast_tvnow();
05092
05093 ast_localtime(&t, &tm, "UTC");
05094
05095 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05096 }
05097
05098 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05099 {
05100 int res;
05101 char fn[PATH_MAX];
05102 char dest[PATH_MAX];
05103
05104 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05105
05106 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05107 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05108 return -1;
05109 }
05110
05111 RETRIEVE(fn, -1, ext, context);
05112 if (ast_fileexists(fn, NULL, NULL) > 0) {
05113 res = ast_stream_and_wait(chan, fn, ecodes);
05114 if (res) {
05115 DISPOSE(fn, -1);
05116 return res;
05117 }
05118 } else {
05119
05120 DISPOSE(fn, -1);
05121 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05122 if (res)
05123 return res;
05124 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05125 if (res)
05126 return res;
05127 }
05128 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05129 return res;
05130 }
05131
05132 static void free_zone(struct vm_zone *z)
05133 {
05134 ast_free(z);
05135 }
05136
05137 #ifdef ODBC_STORAGE
05138 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05139 {
05140 int x = -1;
05141 int res;
05142 SQLHSTMT stmt = NULL;
05143 char sql[PATH_MAX];
05144 char rowdata[20];
05145 char tmp[PATH_MAX] = "";
05146 struct odbc_obj *obj = NULL;
05147 char *context;
05148 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05149
05150 if (newmsgs)
05151 *newmsgs = 0;
05152 if (oldmsgs)
05153 *oldmsgs = 0;
05154 if (urgentmsgs)
05155 *urgentmsgs = 0;
05156
05157
05158 if (ast_strlen_zero(mailbox))
05159 return 0;
05160
05161 ast_copy_string(tmp, mailbox, sizeof(tmp));
05162
05163 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05164 int u, n, o;
05165 char *next, *remaining = tmp;
05166 while ((next = strsep(&remaining, " ,"))) {
05167 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05168 return -1;
05169 }
05170 if (urgentmsgs) {
05171 *urgentmsgs += u;
05172 }
05173 if (newmsgs) {
05174 *newmsgs += n;
05175 }
05176 if (oldmsgs) {
05177 *oldmsgs += o;
05178 }
05179 }
05180 return 0;
05181 }
05182
05183 context = strchr(tmp, '@');
05184 if (context) {
05185 *context = '\0';
05186 context++;
05187 } else
05188 context = "default";
05189
05190 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05191 do {
05192 if (newmsgs) {
05193 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05194 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05195 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05196 break;
05197 }
05198 res = SQLFetch(stmt);
05199 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05200 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05201 break;
05202 }
05203 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05204 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05205 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05206 break;
05207 }
05208 *newmsgs = atoi(rowdata);
05209 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05210 }
05211
05212 if (oldmsgs) {
05213 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05214 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05215 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05216 break;
05217 }
05218 res = SQLFetch(stmt);
05219 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05220 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05221 break;
05222 }
05223 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05224 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05225 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05226 break;
05227 }
05228 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05229 *oldmsgs = atoi(rowdata);
05230 }
05231
05232 if (urgentmsgs) {
05233 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05234 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05235 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05236 break;
05237 }
05238 res = SQLFetch(stmt);
05239 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05240 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05241 break;
05242 }
05243 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05244 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05245 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05246 break;
05247 }
05248 *urgentmsgs = atoi(rowdata);
05249 }
05250
05251 x = 0;
05252 } while (0);
05253 } else {
05254 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05255 }
05256
05257 if (stmt) {
05258 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05259 }
05260 if (obj) {
05261 ast_odbc_release_obj(obj);
05262 }
05263 return x;
05264 }
05265
05266
05267
05268
05269
05270
05271
05272
05273
05274
05275 static int messagecount(const char *context, const char *mailbox, const char *folder)
05276 {
05277 struct odbc_obj *obj = NULL;
05278 int nummsgs = 0;
05279 int res;
05280 SQLHSTMT stmt = NULL;
05281 char sql[PATH_MAX];
05282 char rowdata[20];
05283 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05284 if (!folder)
05285 folder = "INBOX";
05286
05287 if (ast_strlen_zero(mailbox))
05288 return 0;
05289
05290 obj = ast_odbc_request_obj(odbc_database, 0);
05291 if (obj) {
05292 if (!strcmp(folder, "INBOX")) {
05293 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox);
05294 } else {
05295 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05296 }
05297 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05298 if (!stmt) {
05299 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05300 goto yuck;
05301 }
05302 res = SQLFetch(stmt);
05303 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05304 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05305 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05306 goto yuck;
05307 }
05308 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05309 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05310 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05311 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05312 goto yuck;
05313 }
05314 nummsgs = atoi(rowdata);
05315 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05316 } else
05317 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05318
05319 yuck:
05320 if (obj)
05321 ast_odbc_release_obj(obj);
05322 return nummsgs;
05323 }
05324
05325
05326
05327
05328
05329
05330
05331
05332
05333 static int has_voicemail(const char *mailbox, const char *folder)
05334 {
05335 char tmp[256], *tmp2 = tmp, *box, *context;
05336 ast_copy_string(tmp, mailbox, sizeof(tmp));
05337 while ((context = box = strsep(&tmp2, ",&"))) {
05338 strsep(&context, "@");
05339 if (ast_strlen_zero(context))
05340 context = "default";
05341 if (messagecount(context, box, folder))
05342 return 1;
05343 }
05344 return 0;
05345 }
05346 #endif
05347 #ifndef IMAP_STORAGE
05348
05349
05350
05351
05352
05353
05354
05355
05356
05357
05358
05359
05360
05361
05362
05363
05364 static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, const char *flag)
05365 {
05366 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05367 const char *frombox = mbox(vmu, imbox);
05368 const char *userfolder;
05369 int recipmsgnum;
05370 int res = 0;
05371
05372 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05373
05374 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05375 userfolder = "Urgent";
05376 } else {
05377 userfolder = "INBOX";
05378 }
05379
05380 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05381
05382 if (!dir)
05383 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05384 else
05385 ast_copy_string(fromdir, dir, sizeof(fromdir));
05386
05387 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05388 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05389
05390 if (vm_lock_path(todir))
05391 return ERROR_LOCK_PATH;
05392
05393 recipmsgnum = last_message_index(recip, todir) + 1;
05394 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05395 make_file(topath, sizeof(topath), todir, recipmsgnum);
05396 #ifndef ODBC_STORAGE
05397 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05398 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05399 } else {
05400 #endif
05401
05402
05403
05404 copy_plain_file(frompath, topath);
05405 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05406 vm_delete(topath);
05407 #ifndef ODBC_STORAGE
05408 }
05409 #endif
05410 } else {
05411 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05412 res = -1;
05413 }
05414 ast_unlock_path(todir);
05415 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05416 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05417 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05418 flag);
05419
05420 return res;
05421 }
05422 #endif
05423 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05424
05425 static int messagecount(const char *context, const char *mailbox, const char *folder)
05426 {
05427 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05428 }
05429
05430 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05431 {
05432 DIR *dir;
05433 struct dirent *de;
05434 char fn[256];
05435 int ret = 0;
05436
05437
05438 if (ast_strlen_zero(mailbox))
05439 return 0;
05440
05441 if (ast_strlen_zero(folder))
05442 folder = "INBOX";
05443 if (ast_strlen_zero(context))
05444 context = "default";
05445
05446 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05447
05448 if (!(dir = opendir(fn)))
05449 return 0;
05450
05451 while ((de = readdir(dir))) {
05452 if (!strncasecmp(de->d_name, "msg", 3)) {
05453 if (shortcircuit) {
05454 ret = 1;
05455 break;
05456 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05457 ret++;
05458 }
05459 }
05460 }
05461
05462 closedir(dir);
05463
05464 return ret;
05465 }
05466
05467
05468
05469
05470
05471
05472
05473
05474
05475
05476 static int has_voicemail(const char *mailbox, const char *folder)
05477 {
05478 char tmp[256], *tmp2 = tmp, *box, *context;
05479 ast_copy_string(tmp, mailbox, sizeof(tmp));
05480 if (ast_strlen_zero(folder)) {
05481 folder = "INBOX";
05482 }
05483 while ((box = strsep(&tmp2, ",&"))) {
05484 if ((context = strchr(box, '@')))
05485 *context++ = '\0';
05486 else
05487 context = "default";
05488 if (__has_voicemail(context, box, folder, 1))
05489 return 1;
05490
05491 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05492 return 1;
05493 }
05494 }
05495 return 0;
05496 }
05497
05498
05499 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05500 {
05501 char tmp[256];
05502 char *context;
05503
05504
05505 if (ast_strlen_zero(mailbox))
05506 return 0;
05507
05508 if (newmsgs)
05509 *newmsgs = 0;
05510 if (oldmsgs)
05511 *oldmsgs = 0;
05512 if (urgentmsgs)
05513 *urgentmsgs = 0;
05514
05515 if (strchr(mailbox, ',')) {
05516 int tmpnew, tmpold, tmpurgent;
05517 char *mb, *cur;
05518
05519 ast_copy_string(tmp, mailbox, sizeof(tmp));
05520 mb = tmp;
05521 while ((cur = strsep(&mb, ", "))) {
05522 if (!ast_strlen_zero(cur)) {
05523 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05524 return -1;
05525 else {
05526 if (newmsgs)
05527 *newmsgs += tmpnew;
05528 if (oldmsgs)
05529 *oldmsgs += tmpold;
05530 if (urgentmsgs)
05531 *urgentmsgs += tmpurgent;
05532 }
05533 }
05534 }
05535 return 0;
05536 }
05537
05538 ast_copy_string(tmp, mailbox, sizeof(tmp));
05539
05540 if ((context = strchr(tmp, '@')))
05541 *context++ = '\0';
05542 else
05543 context = "default";
05544
05545 if (newmsgs)
05546 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05547 if (oldmsgs)
05548 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05549 if (urgentmsgs)
05550 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05551
05552 return 0;
05553 }
05554
05555 #endif
05556
05557
05558 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05559 {
05560 int urgentmsgs = 0;
05561 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05562 if (newmsgs) {
05563 *newmsgs += urgentmsgs;
05564 }
05565 return res;
05566 }
05567
05568 static void run_externnotify(char *context, char *extension, const char *flag)
05569 {
05570 char arguments[255];
05571 char ext_context[256] = "";
05572 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05573 struct ast_smdi_mwi_message *mwi_msg;
05574
05575 if (!ast_strlen_zero(context))
05576 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05577 else
05578 ast_copy_string(ext_context, extension, sizeof(ext_context));
05579
05580 if (smdi_iface) {
05581 if (ast_app_has_voicemail(ext_context, NULL))
05582 ast_smdi_mwi_set(smdi_iface, extension);
05583 else
05584 ast_smdi_mwi_unset(smdi_iface, extension);
05585
05586 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05587 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05588 if (!strncmp(mwi_msg->cause, "INV", 3))
05589 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05590 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05591 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05592 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05593 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05594 } else {
05595 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05596 }
05597 }
05598
05599 if (!ast_strlen_zero(externnotify)) {
05600 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05601 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05602 } else {
05603 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &",
05604 externnotify, S_OR(context, "\"\""),
05605 extension, newvoicemails,
05606 oldvoicemails, urgentvoicemails);
05607 ast_debug(1, "Executing %s\n", arguments);
05608 ast_safe_system(arguments);
05609 }
05610 }
05611 }
05612
05613
05614
05615
05616
05617
05618 struct leave_vm_options {
05619 unsigned int flags;
05620 signed char record_gain;
05621 char *exitcontext;
05622 };
05623
05624
05625
05626
05627
05628
05629
05630
05631
05632
05633
05634 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05635 {
05636 #ifdef IMAP_STORAGE
05637 int newmsgs, oldmsgs;
05638 #else
05639 char urgdir[PATH_MAX];
05640 #endif
05641 char txtfile[PATH_MAX];
05642 char tmptxtfile[PATH_MAX];
05643 struct vm_state *vms = NULL;
05644 char callerid[256];
05645 FILE *txt;
05646 char date[256];
05647 int txtdes;
05648 int res = 0;
05649 int msgnum;
05650 int duration = 0;
05651 int sound_duration = 0;
05652 int ausemacro = 0;
05653 int ousemacro = 0;
05654 int ouseexten = 0;
05655 char tmpdur[16];
05656 char priority[16];
05657 char origtime[16];
05658 char dir[PATH_MAX];
05659 char tmpdir[PATH_MAX];
05660 char fn[PATH_MAX];
05661 char prefile[PATH_MAX] = "";
05662 char tempfile[PATH_MAX] = "";
05663 char ext_context[256] = "";
05664 char fmt[80];
05665 char *context;
05666 char ecodes[17] = "#";
05667 struct ast_str *tmp = ast_str_create(16);
05668 char *tmpptr;
05669 struct ast_vm_user *vmu;
05670 struct ast_vm_user svm;
05671 const char *category = NULL;
05672 const char *code;
05673 const char *alldtmf = "0123456789ABCD*#";
05674 char flag[80];
05675
05676 if (!tmp) {
05677 return -1;
05678 }
05679
05680 ast_str_set(&tmp, 0, "%s", ext);
05681 ext = ast_str_buffer(tmp);
05682 if ((context = strchr(ext, '@'))) {
05683 *context++ = '\0';
05684 tmpptr = strchr(context, '&');
05685 } else {
05686 tmpptr = strchr(ext, '&');
05687 }
05688
05689 if (tmpptr)
05690 *tmpptr++ = '\0';
05691
05692 ast_channel_lock(chan);
05693 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05694 category = ast_strdupa(category);
05695 }
05696 ast_channel_unlock(chan);
05697
05698 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05699 ast_copy_string(flag, "Urgent", sizeof(flag));
05700 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05701 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05702 } else {
05703 flag[0] = '\0';
05704 }
05705
05706 ast_debug(3, "Before find_user\n");
05707 if (!(vmu = find_user(&svm, context, ext))) {
05708 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05709 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05710 ast_free(tmp);
05711 return res;
05712 }
05713
05714 if (strcmp(vmu->context, "default"))
05715 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05716 else
05717 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05718
05719
05720
05721
05722
05723
05724 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05725 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05726 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05727 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05728 }
05729
05730
05731
05732
05733 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05734 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05735 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05736 ast_free(tmp);
05737 return -1;
05738 }
05739 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05740 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05741 ast_copy_string(prefile, tempfile, sizeof(prefile));
05742
05743 DISPOSE(tempfile, -1);
05744
05745 #ifndef IMAP_STORAGE
05746 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05747 #else
05748 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05749 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05750 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05751 }
05752 #endif
05753
05754
05755 if (ast_test_flag(vmu, VM_OPERATOR)) {
05756 if (!ast_strlen_zero(vmu->exit)) {
05757 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05758 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05759 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05760 ouseexten = 1;
05761 }
05762 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05763 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05764 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05765 ouseexten = 1;
05766 } else if (!ast_strlen_zero(chan->macrocontext)
05767 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05768 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05769 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05770 ousemacro = 1;
05771 }
05772 }
05773
05774 if (!ast_strlen_zero(vmu->exit)) {
05775 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05776 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05777 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05778 }
05779 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05780 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05781 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05782 } else if (!ast_strlen_zero(chan->macrocontext)
05783 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05784 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05785 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05786 ausemacro = 1;
05787 }
05788
05789 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05790 for (code = alldtmf; *code; code++) {
05791 char e[2] = "";
05792 e[0] = *code;
05793 if (strchr(ecodes, e[0]) == NULL
05794 && ast_canmatch_extension(chan,
05795 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05796 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05797 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05798 }
05799 }
05800 }
05801
05802
05803 if (!ast_strlen_zero(prefile)) {
05804 #ifdef ODBC_STORAGE
05805 int success =
05806 #endif
05807 RETRIEVE(prefile, -1, ext, context);
05808 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05809 if (ast_streamfile(chan, prefile, chan->language) > -1)
05810 res = ast_waitstream(chan, ecodes);
05811 #ifdef ODBC_STORAGE
05812 if (success == -1) {
05813
05814 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05815 store_file(prefile, vmu->mailbox, vmu->context, -1);
05816 }
05817 #endif
05818 } else {
05819 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05820 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05821 }
05822 DISPOSE(prefile, -1);
05823 if (res < 0) {
05824 ast_debug(1, "Hang up during prefile playback\n");
05825 free_user(vmu);
05826 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05827 ast_free(tmp);
05828 return -1;
05829 }
05830 }
05831 if (res == '#') {
05832
05833 ast_set_flag(options, OPT_SILENT);
05834 res = 0;
05835 }
05836
05837 if (vmu->maxmsg == 0) {
05838 if (option_debug > 2)
05839 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05840 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05841 goto leave_vm_out;
05842 }
05843 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05844 res = ast_stream_and_wait(chan, INTRO, ecodes);
05845 if (res == '#') {
05846 ast_set_flag(options, OPT_SILENT);
05847 res = 0;
05848 }
05849 }
05850 if (res > 0)
05851 ast_stopstream(chan);
05852
05853
05854 if (res == '*') {
05855 chan->exten[0] = 'a';
05856 chan->exten[1] = '\0';
05857 if (!ast_strlen_zero(vmu->exit)) {
05858 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05859 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05860 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05861 }
05862 chan->priority = 0;
05863 free_user(vmu);
05864 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05865 ast_free(tmp);
05866 return 0;
05867 }
05868
05869
05870 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05871 transfer:
05872 if (ouseexten || ousemacro) {
05873 chan->exten[0] = 'o';
05874 chan->exten[1] = '\0';
05875 if (!ast_strlen_zero(vmu->exit)) {
05876 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05877 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05878 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05879 }
05880 ast_play_and_wait(chan, "transfer");
05881 chan->priority = 0;
05882 free_user(vmu);
05883 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05884 }
05885 ast_free(tmp);
05886 return OPERATOR_EXIT;
05887 }
05888
05889
05890 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05891 if (!ast_strlen_zero(options->exitcontext)) {
05892 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05893 }
05894 free_user(vmu);
05895 ast_free(tmp);
05896 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05897 return res;
05898 }
05899
05900 if (res < 0) {
05901 free_user(vmu);
05902 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05903 ast_free(tmp);
05904 return -1;
05905 }
05906
05907 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05908 if (!ast_strlen_zero(fmt)) {
05909 msgnum = 0;
05910
05911 #ifdef IMAP_STORAGE
05912
05913
05914 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05915 if (res < 0) {
05916 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05917 ast_free(tmp);
05918 return -1;
05919 }
05920 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05921
05922
05923
05924
05925 if (!(vms = create_vm_state_from_user(vmu))) {
05926 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05927 ast_free(tmp);
05928 return -1;
05929 }
05930 }
05931 vms->newmessages++;
05932
05933
05934 msgnum = newmsgs + oldmsgs;
05935 ast_debug(3, "Messagecount set to %d\n", msgnum);
05936 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05937
05938 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05939
05940 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05941 goto leave_vm_out;
05942 }
05943 #else
05944 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05945 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05946 if (!res)
05947 res = ast_waitstream(chan, "");
05948 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05949 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05950 inprocess_count(vmu->mailbox, vmu->context, -1);
05951 goto leave_vm_out;
05952 }
05953
05954 #endif
05955 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05956 txtdes = mkstemp(tmptxtfile);
05957 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05958 if (txtdes < 0) {
05959 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05960 if (!res)
05961 res = ast_waitstream(chan, "");
05962 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05963 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05964 inprocess_count(vmu->mailbox, vmu->context, -1);
05965 goto leave_vm_out;
05966 }
05967
05968
05969 if (res >= 0) {
05970
05971 res = ast_stream_and_wait(chan, "beep", "");
05972 }
05973
05974
05975 if (ast_check_realtime("voicemail_data")) {
05976 snprintf(priority, sizeof(priority), "%d", chan->priority);
05977 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05978 get_date(date, sizeof(date));
05979 ast_callerid_merge(callerid, sizeof(callerid),
05980 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05981 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05982 "Unknown");
05983 ast_store_realtime("voicemail_data",
05984 "origmailbox", ext,
05985 "context", chan->context,
05986 "macrocontext", chan->macrocontext,
05987 "exten", chan->exten,
05988 "priority", priority,
05989 "callerchan", chan->name,
05990 "callerid", callerid,
05991 "origdate", date,
05992 "origtime", origtime,
05993 "category", S_OR(category, ""),
05994 "filename", tmptxtfile,
05995 SENTINEL);
05996 }
05997
05998
05999 txt = fdopen(txtdes, "w+");
06000 if (txt) {
06001 get_date(date, sizeof(date));
06002 ast_callerid_merge(callerid, sizeof(callerid),
06003 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06004 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06005 "Unknown");
06006 fprintf(txt,
06007 ";\n"
06008 "; Message Information file\n"
06009 ";\n"
06010 "[message]\n"
06011 "origmailbox=%s\n"
06012 "context=%s\n"
06013 "macrocontext=%s\n"
06014 "exten=%s\n"
06015 "rdnis=%s\n"
06016 "priority=%d\n"
06017 "callerchan=%s\n"
06018 "callerid=%s\n"
06019 "origdate=%s\n"
06020 "origtime=%ld\n"
06021 "category=%s\n",
06022 ext,
06023 chan->context,
06024 chan->macrocontext,
06025 chan->exten,
06026 S_COR(chan->redirecting.from.number.valid,
06027 chan->redirecting.from.number.str, "unknown"),
06028 chan->priority,
06029 chan->name,
06030 callerid,
06031 date, (long) time(NULL),
06032 category ? category : "");
06033 } else {
06034 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
06035 inprocess_count(vmu->mailbox, vmu->context, -1);
06036 if (ast_check_realtime("voicemail_data")) {
06037 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06038 }
06039 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
06040 goto leave_vm_out;
06041 }
06042 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
06043
06044 if (txt) {
06045 fprintf(txt, "flag=%s\n", flag);
06046 if (sound_duration < vmu->minsecs) {
06047 fclose(txt);
06048 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06049 ast_filedelete(tmptxtfile, NULL);
06050 unlink(tmptxtfile);
06051 if (ast_check_realtime("voicemail_data")) {
06052 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06053 }
06054 inprocess_count(vmu->mailbox, vmu->context, -1);
06055 } else {
06056 fprintf(txt, "duration=%d\n", duration);
06057 fclose(txt);
06058 if (vm_lock_path(dir)) {
06059 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06060
06061 ast_filedelete(tmptxtfile, NULL);
06062 unlink(tmptxtfile);
06063 inprocess_count(vmu->mailbox, vmu->context, -1);
06064 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06065 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06066 unlink(tmptxtfile);
06067 ast_unlock_path(dir);
06068 inprocess_count(vmu->mailbox, vmu->context, -1);
06069 if (ast_check_realtime("voicemail_data")) {
06070 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06071 }
06072 } else {
06073 #ifndef IMAP_STORAGE
06074 msgnum = last_message_index(vmu, dir) + 1;
06075 #endif
06076 make_file(fn, sizeof(fn), dir, msgnum);
06077
06078
06079 #ifndef IMAP_STORAGE
06080 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06081 #else
06082 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06083 #endif
06084
06085 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06086 ast_filerename(tmptxtfile, fn, NULL);
06087 rename(tmptxtfile, txtfile);
06088 inprocess_count(vmu->mailbox, vmu->context, -1);
06089
06090
06091
06092 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06093 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06094
06095 ast_unlock_path(dir);
06096 if (ast_check_realtime("voicemail_data")) {
06097 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06098 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06099 }
06100
06101
06102
06103 if (ast_fileexists(fn, NULL, NULL) > 0) {
06104 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06105 }
06106
06107
06108 while (tmpptr) {
06109 struct ast_vm_user recipu, *recip;
06110 char *exten, *cntx;
06111
06112 exten = strsep(&tmpptr, "&");
06113 cntx = strchr(exten, '@');
06114 if (cntx) {
06115 *cntx = '\0';
06116 cntx++;
06117 }
06118 if ((recip = find_user(&recipu, cntx, exten))) {
06119 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06120 free_user(recip);
06121 }
06122 }
06123 #ifndef IMAP_STORAGE
06124 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06125
06126 char sfn[PATH_MAX];
06127 char dfn[PATH_MAX];
06128 int x;
06129
06130 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06131 x = last_message_index(vmu, urgdir) + 1;
06132 make_file(sfn, sizeof(sfn), dir, msgnum);
06133 make_file(dfn, sizeof(dfn), urgdir, x);
06134 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06135 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06136
06137 ast_copy_string(fn, dfn, sizeof(fn));
06138 msgnum = x;
06139 }
06140 #endif
06141
06142 if (ast_fileexists(fn, NULL, NULL)) {
06143 #ifdef IMAP_STORAGE
06144 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06145 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06146 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06147 flag);
06148 #else
06149 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06150 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06151 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06152 flag);
06153 #endif
06154 }
06155
06156
06157 if (ast_fileexists(fn, NULL, NULL)) {
06158 DISPOSE(dir, msgnum);
06159 }
06160 }
06161 }
06162 } else {
06163 inprocess_count(vmu->mailbox, vmu->context, -1);
06164 }
06165 if (res == '0') {
06166 goto transfer;
06167 } else if (res > 0 && res != 't')
06168 res = 0;
06169
06170 if (sound_duration < vmu->minsecs)
06171
06172 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06173 else
06174 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06175 } else
06176 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06177 leave_vm_out:
06178 free_user(vmu);
06179
06180 #ifdef IMAP_STORAGE
06181
06182 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06183 if (expungeonhangup == 1) {
06184 ast_mutex_lock(&vms->lock);
06185 #ifdef HAVE_IMAP_TK2006
06186 if (LEVELUIDPLUS (vms->mailstream)) {
06187 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06188 } else
06189 #endif
06190 mail_expunge(vms->mailstream);
06191 ast_mutex_unlock(&vms->lock);
06192 }
06193 #endif
06194
06195 ast_free(tmp);
06196 return res;
06197 }
06198
06199 #if !defined(IMAP_STORAGE)
06200 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06201 {
06202
06203
06204 int x, dest;
06205 char sfn[PATH_MAX];
06206 char dfn[PATH_MAX];
06207
06208 if (vm_lock_path(dir)) {
06209 return ERROR_LOCK_PATH;
06210 }
06211
06212 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06213 make_file(sfn, sizeof(sfn), dir, x);
06214 if (EXISTS(dir, x, sfn, NULL)) {
06215
06216 if (x != dest) {
06217 make_file(dfn, sizeof(dfn), dir, dest);
06218 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06219 }
06220
06221 dest++;
06222 }
06223 }
06224 ast_unlock_path(dir);
06225
06226 return dest;
06227 }
06228 #endif
06229
06230 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06231 {
06232 int d;
06233 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06234 return d;
06235 }
06236
06237 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06238 {
06239 #ifdef IMAP_STORAGE
06240
06241
06242 char sequence[10];
06243 char mailbox[256];
06244 int res;
06245
06246
06247 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06248
06249 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06250 ast_mutex_lock(&vms->lock);
06251
06252 if (box == OLD_FOLDER) {
06253 mail_setflag(vms->mailstream, sequence, "\\Seen");
06254 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06255 } else if (box == NEW_FOLDER) {
06256 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06257 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06258 }
06259 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06260 ast_mutex_unlock(&vms->lock);
06261 return 0;
06262 }
06263
06264 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06265 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06266 if (mail_create(vms->mailstream, mailbox) == NIL)
06267 ast_debug(5, "Folder exists.\n");
06268 else
06269 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06270 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06271 ast_mutex_unlock(&vms->lock);
06272 return res;
06273 #else
06274 char *dir = vms->curdir;
06275 char *username = vms->username;
06276 char *context = vmu->context;
06277 char sfn[PATH_MAX];
06278 char dfn[PATH_MAX];
06279 char ddir[PATH_MAX];
06280 const char *dbox = mbox(vmu, box);
06281 int x, i;
06282 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06283
06284 if (vm_lock_path(ddir))
06285 return ERROR_LOCK_PATH;
06286
06287 x = last_message_index(vmu, ddir) + 1;
06288
06289 if (box == 10 && x >= vmu->maxdeletedmsg) {
06290 x--;
06291 for (i = 1; i <= x; i++) {
06292
06293 make_file(sfn, sizeof(sfn), ddir, i);
06294 make_file(dfn, sizeof(dfn), ddir, i - 1);
06295 if (EXISTS(ddir, i, sfn, NULL)) {
06296 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06297 } else
06298 break;
06299 }
06300 } else {
06301 if (x >= vmu->maxmsg) {
06302 ast_unlock_path(ddir);
06303 return -1;
06304 }
06305 }
06306 make_file(sfn, sizeof(sfn), dir, msg);
06307 make_file(dfn, sizeof(dfn), ddir, x);
06308 if (strcmp(sfn, dfn)) {
06309 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06310 }
06311 ast_unlock_path(ddir);
06312 #endif
06313 return 0;
06314 }
06315
06316 static int adsi_logo(unsigned char *buf)
06317 {
06318 int bytes = 0;
06319 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06320 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06321 return bytes;
06322 }
06323
06324 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06325 {
06326 unsigned char buf[256];
06327 int bytes = 0;
06328 int x;
06329 char num[5];
06330
06331 *useadsi = 0;
06332 bytes += ast_adsi_data_mode(buf + bytes);
06333 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06334
06335 bytes = 0;
06336 bytes += adsi_logo(buf);
06337 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06338 #ifdef DISPLAY
06339 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06340 #endif
06341 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06342 bytes += ast_adsi_data_mode(buf + bytes);
06343 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06344
06345 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06346 bytes = 0;
06347 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06348 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06349 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06350 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06351 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06352 return 0;
06353 }
06354
06355 #ifdef DISPLAY
06356
06357 bytes = 0;
06358 bytes += ast_adsi_logo(buf);
06359 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06360 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06361 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06362 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06363 #endif
06364 bytes = 0;
06365 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06366 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06367 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06368 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06369 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06370 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06371 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06372
06373 #ifdef DISPLAY
06374
06375 bytes = 0;
06376 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06377 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06378
06379 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06380 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06381 #endif
06382
06383 bytes = 0;
06384
06385 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06386 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06387 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06388 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06389 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06390 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06391 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06392
06393 #ifdef DISPLAY
06394
06395 bytes = 0;
06396 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06397 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06398 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06399 #endif
06400
06401 bytes = 0;
06402 for (x = 0; x < 5; x++) {
06403 snprintf(num, sizeof(num), "%d", x);
06404 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06405 }
06406 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06407 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06408
06409 #ifdef DISPLAY
06410
06411 bytes = 0;
06412 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06413 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06414 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06415 #endif
06416
06417 if (ast_adsi_end_download(chan)) {
06418 bytes = 0;
06419 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06420 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06421 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06422 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06423 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06424 return 0;
06425 }
06426 bytes = 0;
06427 bytes += ast_adsi_download_disconnect(buf + bytes);
06428 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06429 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06430
06431 ast_debug(1, "Done downloading scripts...\n");
06432
06433 #ifdef DISPLAY
06434
06435 bytes = 0;
06436 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06437 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06438 #endif
06439 ast_debug(1, "Restarting session...\n");
06440
06441 bytes = 0;
06442
06443 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06444 *useadsi = 1;
06445 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06446 } else
06447 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06448
06449 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06450 return 0;
06451 }
06452
06453 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06454 {
06455 int x;
06456 if (!ast_adsi_available(chan))
06457 return;
06458 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06459 if (x < 0)
06460 return;
06461 if (!x) {
06462 if (adsi_load_vmail(chan, useadsi)) {
06463 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06464 return;
06465 }
06466 } else
06467 *useadsi = 1;
06468 }
06469
06470 static void adsi_login(struct ast_channel *chan)
06471 {
06472 unsigned char buf[256];
06473 int bytes = 0;
06474 unsigned char keys[8];
06475 int x;
06476 if (!ast_adsi_available(chan))
06477 return;
06478
06479 for (x = 0; x < 8; x++)
06480 keys[x] = 0;
06481
06482 keys[3] = ADSI_KEY_APPS + 3;
06483
06484 bytes += adsi_logo(buf + bytes);
06485 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06486 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06487 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06488 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06489 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06490 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06491 bytes += ast_adsi_set_keys(buf + bytes, keys);
06492 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06493 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06494 }
06495
06496 static void adsi_password(struct ast_channel *chan)
06497 {
06498 unsigned char buf[256];
06499 int bytes = 0;
06500 unsigned char keys[8];
06501 int x;
06502 if (!ast_adsi_available(chan))
06503 return;
06504
06505 for (x = 0; x < 8; x++)
06506 keys[x] = 0;
06507
06508 keys[3] = ADSI_KEY_APPS + 3;
06509
06510 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06511 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06512 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06513 bytes += ast_adsi_set_keys(buf + bytes, keys);
06514 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06515 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06516 }
06517
06518 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06519 {
06520 unsigned char buf[256];
06521 int bytes = 0;
06522 unsigned char keys[8];
06523 int x, y;
06524
06525 if (!ast_adsi_available(chan))
06526 return;
06527
06528 for (x = 0; x < 5; x++) {
06529 y = ADSI_KEY_APPS + 12 + start + x;
06530 if (y > ADSI_KEY_APPS + 12 + 4)
06531 y = 0;
06532 keys[x] = ADSI_KEY_SKT | y;
06533 }
06534 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06535 keys[6] = 0;
06536 keys[7] = 0;
06537
06538 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06539 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06540 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06541 bytes += ast_adsi_set_keys(buf + bytes, keys);
06542 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06543
06544 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06545 }
06546
06547 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06548 {
06549 int bytes = 0;
06550 unsigned char buf[256];
06551 char buf1[256], buf2[256];
06552 char fn2[PATH_MAX];
06553
06554 char cid[256] = "";
06555 char *val;
06556 char *name, *num;
06557 char datetime[21] = "";
06558 FILE *f;
06559
06560 unsigned char keys[8];
06561
06562 int x;
06563
06564 if (!ast_adsi_available(chan))
06565 return;
06566
06567
06568 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06569 f = fopen(fn2, "r");
06570 if (f) {
06571 while (!feof(f)) {
06572 if (!fgets((char *) buf, sizeof(buf), f)) {
06573 continue;
06574 }
06575 if (!feof(f)) {
06576 char *stringp = NULL;
06577 stringp = (char *) buf;
06578 strsep(&stringp, "=");
06579 val = strsep(&stringp, "=");
06580 if (!ast_strlen_zero(val)) {
06581 if (!strcmp((char *) buf, "callerid"))
06582 ast_copy_string(cid, val, sizeof(cid));
06583 if (!strcmp((char *) buf, "origdate"))
06584 ast_copy_string(datetime, val, sizeof(datetime));
06585 }
06586 }
06587 }
06588 fclose(f);
06589 }
06590
06591 for (x = 0; x < 5; x++)
06592 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06593 keys[6] = 0x0;
06594 keys[7] = 0x0;
06595
06596 if (!vms->curmsg) {
06597
06598 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06599 }
06600 if (vms->curmsg >= vms->lastmsg) {
06601
06602 if (vms->curmsg) {
06603
06604 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06605 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06606
06607 } else {
06608
06609 keys[3] = 1;
06610 }
06611 }
06612
06613 if (!ast_strlen_zero(cid)) {
06614 ast_callerid_parse(cid, &name, &num);
06615 if (!name)
06616 name = num;
06617 } else
06618 name = "Unknown Caller";
06619
06620
06621 #ifdef IMAP_STORAGE
06622 ast_mutex_lock(&vms->lock);
06623 #endif
06624 if (vms->deleted[vms->curmsg]) {
06625 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06626 }
06627 #ifdef IMAP_STORAGE
06628 ast_mutex_unlock(&vms->lock);
06629 #endif
06630
06631
06632 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06633 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06634 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06635 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06636
06637 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06638 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06639 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06640 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06641 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06642 bytes += ast_adsi_set_keys(buf + bytes, keys);
06643 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06644
06645 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06646 }
06647
06648 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06649 {
06650 int bytes = 0;
06651 unsigned char buf[256];
06652 unsigned char keys[8];
06653
06654 int x;
06655
06656 if (!ast_adsi_available(chan))
06657 return;
06658
06659
06660 for (x = 0; x < 5; x++)
06661 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06662
06663 keys[6] = 0x0;
06664 keys[7] = 0x0;
06665
06666 if (!vms->curmsg) {
06667
06668 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06669 }
06670 if (vms->curmsg >= vms->lastmsg) {
06671
06672 if (vms->curmsg) {
06673
06674 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06675 } else {
06676
06677 keys[3] = 1;
06678 }
06679 }
06680
06681
06682 #ifdef IMAP_STORAGE
06683 ast_mutex_lock(&vms->lock);
06684 #endif
06685 if (vms->deleted[vms->curmsg]) {
06686 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06687 }
06688 #ifdef IMAP_STORAGE
06689 ast_mutex_unlock(&vms->lock);
06690 #endif
06691
06692
06693 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06694 bytes += ast_adsi_set_keys(buf + bytes, keys);
06695 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06696
06697 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06698 }
06699
06700 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06701 {
06702 unsigned char buf[256] = "";
06703 char buf1[256] = "", buf2[256] = "";
06704 int bytes = 0;
06705 unsigned char keys[8];
06706 int x;
06707
06708 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06709 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06710 if (!ast_adsi_available(chan))
06711 return;
06712 if (vms->newmessages) {
06713 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06714 if (vms->oldmessages) {
06715 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06716 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06717 } else {
06718 snprintf(buf2, sizeof(buf2), "%s.", newm);
06719 }
06720 } else if (vms->oldmessages) {
06721 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06722 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06723 } else {
06724 strcpy(buf1, "You have no messages.");
06725 buf2[0] = ' ';
06726 buf2[1] = '\0';
06727 }
06728 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06729 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06730 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06731
06732 for (x = 0; x < 6; x++)
06733 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06734 keys[6] = 0;
06735 keys[7] = 0;
06736
06737
06738 if (vms->lastmsg < 0)
06739 keys[0] = 1;
06740 bytes += ast_adsi_set_keys(buf + bytes, keys);
06741
06742 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06743
06744 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06745 }
06746
06747 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06748 {
06749 unsigned char buf[256] = "";
06750 char buf1[256] = "", buf2[256] = "";
06751 int bytes = 0;
06752 unsigned char keys[8];
06753 int x;
06754
06755 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06756
06757 if (!ast_adsi_available(chan))
06758 return;
06759
06760
06761 for (x = 0; x < 6; x++)
06762 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06763
06764 keys[6] = 0;
06765 keys[7] = 0;
06766
06767 if ((vms->lastmsg + 1) < 1)
06768 keys[0] = 0;
06769
06770 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06771 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06772
06773 if (vms->lastmsg + 1)
06774 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06775 else
06776 strcpy(buf2, "no messages.");
06777 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06778 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06779 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06780 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06781 bytes += ast_adsi_set_keys(buf + bytes, keys);
06782
06783 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06784
06785 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06786
06787 }
06788
06789
06790
06791
06792
06793
06794
06795
06796
06797
06798
06799
06800
06801
06802
06803 static void adsi_goodbye(struct ast_channel *chan)
06804 {
06805 unsigned char buf[256];
06806 int bytes = 0;
06807
06808 if (!ast_adsi_available(chan))
06809 return;
06810 bytes += adsi_logo(buf + bytes);
06811 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06812 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06813 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06814 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06815
06816 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06817 }
06818
06819
06820
06821
06822
06823 static int get_folder(struct ast_channel *chan, int start)
06824 {
06825 int x;
06826 int d;
06827 char fn[PATH_MAX];
06828 d = ast_play_and_wait(chan, "vm-press");
06829 if (d)
06830 return d;
06831 for (x = start; x < 5; x++) {
06832 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06833 return d;
06834 d = ast_play_and_wait(chan, "vm-for");
06835 if (d)
06836 return d;
06837 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06838
06839
06840
06841
06842 if (x == 0) {
06843 if (ast_fileexists(fn, NULL, NULL)) {
06844 d = vm_play_folder_name(chan, fn);
06845 } else {
06846 ast_verb(1, "failed to find %s\n", fn);
06847 d = vm_play_folder_name(chan, "vm-INBOX");
06848 }
06849 } else {
06850 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06851 d = vm_play_folder_name(chan, fn);
06852 }
06853
06854 if (d)
06855 return d;
06856 d = ast_waitfordigit(chan, 500);
06857 if (d)
06858 return d;
06859 }
06860
06861 d = ast_play_and_wait(chan, "vm-tocancel");
06862 if (d)
06863 return d;
06864 d = ast_waitfordigit(chan, 4000);
06865 return d;
06866 }
06867
06868
06869
06870
06871
06872
06873
06874
06875
06876
06877
06878
06879
06880 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06881 {
06882 int res = 0;
06883 int loops = 0;
06884
06885 res = ast_play_and_wait(chan, fn);
06886 while (((res < '0') || (res > '9')) &&
06887 (res != '#') && (res >= 0) &&
06888 loops < 4) {
06889 res = get_folder(chan, 0);
06890 loops++;
06891 }
06892 if (loops == 4) {
06893 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06894 return '#';
06895 }
06896 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06897 return res;
06898 }
06899
06900
06901
06902
06903
06904
06905
06906
06907
06908
06909
06910
06911
06912
06913
06914
06915
06916
06917
06918 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06919 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06920 {
06921 int cmd = 0;
06922 int retries = 0, prepend_duration = 0, already_recorded = 0;
06923 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06924 char textfile[PATH_MAX];
06925 struct ast_config *msg_cfg;
06926 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06927 #ifndef IMAP_STORAGE
06928 signed char zero_gain = 0;
06929 #endif
06930 const char *duration_str;
06931
06932
06933 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06934 strcpy(textfile, msgfile);
06935 strcpy(backup, msgfile);
06936 strcpy(backup_textfile, msgfile);
06937 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06938 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06939 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06940
06941 if ((msg_cfg = ast_config_load(textfile, config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06942 *duration = atoi(duration_str);
06943 } else {
06944 *duration = 0;
06945 }
06946
06947 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06948 if (cmd)
06949 retries = 0;
06950 switch (cmd) {
06951 case '1':
06952
06953 #ifdef IMAP_STORAGE
06954
06955 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06956 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06957 ast_play_and_wait(chan, INTRO);
06958 ast_play_and_wait(chan, "beep");
06959 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06960 if (cmd == -1) {
06961 break;
06962 }
06963 cmd = 't';
06964 #else
06965
06966
06967
06968 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06969 strcpy(textfile, msgfile);
06970 strncat(textfile, ".txt", sizeof(textfile) - 1);
06971 *duration = 0;
06972
06973
06974 if (!valid_config(msg_cfg)) {
06975 cmd = 0;
06976 break;
06977 }
06978
06979
06980 #ifndef IMAP_STORAGE
06981 if (already_recorded) {
06982 ast_filecopy(backup, msgfile, NULL);
06983 copy(backup_textfile, textfile);
06984 }
06985 else {
06986 ast_filecopy(msgfile, backup, NULL);
06987 copy(textfile, backup_textfile);
06988 }
06989 #endif
06990 already_recorded = 1;
06991
06992 if (record_gain)
06993 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06994
06995 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06996
06997 if (cmd == 'S') {
06998 ast_stream_and_wait(chan, vm_pls_try_again, "");
06999 ast_stream_and_wait(chan, vm_prepend_timeout, "");
07000 ast_filerename(backup, msgfile, NULL);
07001 }
07002
07003 if (record_gain)
07004 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
07005
07006
07007 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
07008 *duration = atoi(duration_str);
07009
07010 if (prepend_duration) {
07011 struct ast_category *msg_cat;
07012
07013 char duration_buf[12];
07014
07015 *duration += prepend_duration;
07016 msg_cat = ast_category_get(msg_cfg, "message");
07017 snprintf(duration_buf, 11, "%ld", *duration);
07018 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
07019 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
07020 }
07021 }
07022
07023 #endif
07024 break;
07025 case '2':
07026
07027 #ifdef IMAP_STORAGE
07028 *vms->introfn = '\0';
07029 #endif
07030 cmd = 't';
07031 break;
07032 case '*':
07033 cmd = '*';
07034 break;
07035 default:
07036
07037 already_recorded = 0;
07038
07039 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
07040
07041 if (!cmd) {
07042 cmd = ast_play_and_wait(chan, "vm-starmain");
07043
07044 }
07045 if (!cmd) {
07046 cmd = ast_waitfordigit(chan, 6000);
07047 }
07048 if (!cmd) {
07049 retries++;
07050 }
07051 if (retries > 3) {
07052 cmd = '*';
07053 }
07054 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07055 }
07056 }
07057
07058 if (valid_config(msg_cfg))
07059 ast_config_destroy(msg_cfg);
07060 if (prepend_duration)
07061 *duration = prepend_duration;
07062
07063 if (already_recorded && cmd == -1) {
07064
07065 ast_filerename(backup, msgfile, NULL);
07066 rename(backup_textfile, textfile);
07067 }
07068
07069 if (cmd == 't' || cmd == 'S')
07070 cmd = 0;
07071 return cmd;
07072 }
07073
07074 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07075 {
07076 struct ast_event *event;
07077 char *mailbox, *context;
07078
07079
07080 context = mailbox = ast_strdupa(box);
07081 strsep(&context, "@");
07082 if (ast_strlen_zero(context))
07083 context = "default";
07084
07085 if (!(event = ast_event_new(AST_EVENT_MWI,
07086 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07087 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07088 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07089 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07090 AST_EVENT_IE_END))) {
07091 return;
07092 }
07093
07094 ast_event_queue_and_cache(event);
07095 }
07096
07097
07098
07099
07100
07101
07102
07103
07104
07105
07106
07107
07108
07109
07110
07111 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag)
07112 {
07113 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07114 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07115 const char *category;
07116 char *myserveremail = serveremail;
07117
07118 ast_channel_lock(chan);
07119 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07120 category = ast_strdupa(category);
07121 }
07122 ast_channel_unlock(chan);
07123
07124 #ifndef IMAP_STORAGE
07125 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07126 #else
07127 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07128 #endif
07129 make_file(fn, sizeof(fn), todir, msgnum);
07130 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07131
07132 if (!ast_strlen_zero(vmu->attachfmt)) {
07133 if (strstr(fmt, vmu->attachfmt))
07134 fmt = vmu->attachfmt;
07135 else
07136 ast_log(AST_LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'. Falling back to default format for '%s@%s'.\n", vmu->attachfmt, fmt, vmu->mailbox, vmu->context);
07137 }
07138
07139
07140 fmt = ast_strdupa(fmt);
07141 stringp = fmt;
07142 strsep(&stringp, "|");
07143
07144 if (!ast_strlen_zero(vmu->serveremail))
07145 myserveremail = vmu->serveremail;
07146
07147 if (!ast_strlen_zero(vmu->email)) {
07148 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07149
07150 if (attach_user_voicemail)
07151 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07152
07153
07154 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07155
07156 if (attach_user_voicemail)
07157 DISPOSE(todir, msgnum);
07158 }
07159
07160 if (!ast_strlen_zero(vmu->pager)) {
07161 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07162 }
07163
07164 if (ast_test_flag(vmu, VM_DELETE))
07165 DELETE(todir, msgnum, fn, vmu);
07166
07167
07168 if (ast_app_has_voicemail(ext_context, NULL))
07169 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07170
07171 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07172
07173 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
07174 run_externnotify(vmu->context, vmu->mailbox, flag);
07175
07176 #ifdef IMAP_STORAGE
07177 vm_delete(fn);
07178 if (ast_test_flag(vmu, VM_DELETE)) {
07179 vm_imap_delete(NULL, vms->curmsg, vmu);
07180 vms->newmessages--;
07181 }
07182 #endif
07183
07184 return 0;
07185 }
07186
07187
07188
07189
07190
07191
07192
07193
07194
07195
07196
07197
07198
07199
07200
07201
07202
07203
07204
07205
07206
07207
07208
07209
07210
07211
07212
07213
07214 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent)
07215 {
07216 #ifdef IMAP_STORAGE
07217 int todircount = 0;
07218 struct vm_state *dstvms;
07219 #endif
07220 char username[70]="";
07221 char fn[PATH_MAX];
07222 char ecodes[16] = "#";
07223 int res = 0, cmd = 0;
07224 struct ast_vm_user *receiver = NULL, *vmtmp;
07225 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07226 char *stringp;
07227 const char *s;
07228 int saved_messages = 0;
07229 int valid_extensions = 0;
07230 char *dir;
07231 int curmsg;
07232 char urgent_str[7] = "";
07233 int prompt_played = 0;
07234 #ifndef IMAP_STORAGE
07235 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07236 #endif
07237 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07238 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07239 }
07240
07241 if (vms == NULL) return -1;
07242 dir = vms->curdir;
07243 curmsg = vms->curmsg;
07244
07245 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07246 while (!res && !valid_extensions) {
07247 int use_directory = 0;
07248 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07249 int done = 0;
07250 int retries = 0;
07251 cmd = 0;
07252 while ((cmd >= 0) && !done ){
07253 if (cmd)
07254 retries = 0;
07255 switch (cmd) {
07256 case '1':
07257 use_directory = 0;
07258 done = 1;
07259 break;
07260 case '2':
07261 use_directory = 1;
07262 done = 1;
07263 break;
07264 case '*':
07265 cmd = 't';
07266 done = 1;
07267 break;
07268 default:
07269
07270 cmd = ast_play_and_wait(chan, "vm-forward");
07271 if (!cmd) {
07272 cmd = ast_waitfordigit(chan, 3000);
07273 }
07274 if (!cmd) {
07275 retries++;
07276 }
07277 if (retries > 3) {
07278 cmd = 't';
07279 done = 1;
07280 }
07281 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07282 }
07283 }
07284 if (cmd < 0 || cmd == 't')
07285 break;
07286 }
07287
07288 if (use_directory) {
07289
07290
07291 char old_context[sizeof(chan->context)];
07292 char old_exten[sizeof(chan->exten)];
07293 int old_priority;
07294 struct ast_app* directory_app;
07295
07296 directory_app = pbx_findapp("Directory");
07297 if (directory_app) {
07298 char vmcontext[256];
07299
07300 memcpy(old_context, chan->context, sizeof(chan->context));
07301 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07302 old_priority = chan->priority;
07303
07304
07305 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07306 res = pbx_exec(chan, directory_app, vmcontext);
07307
07308 ast_copy_string(username, chan->exten, sizeof(username));
07309
07310
07311 memcpy(chan->context, old_context, sizeof(chan->context));
07312 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07313 chan->priority = old_priority;
07314 } else {
07315 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07316 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07317 }
07318 } else {
07319
07320 res = ast_streamfile(chan, "vm-extension", chan->language);
07321 prompt_played++;
07322 if (res || prompt_played > 4)
07323 break;
07324 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07325 break;
07326 }
07327
07328
07329 if (ast_strlen_zero(username))
07330 continue;
07331 stringp = username;
07332 s = strsep(&stringp, "*");
07333
07334 valid_extensions = 1;
07335 while (s) {
07336 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07337 int oldmsgs;
07338 int newmsgs;
07339 int capacity;
07340 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07341 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07342
07343 res = ast_play_and_wait(chan, "pbx-invalid");
07344 valid_extensions = 0;
07345 break;
07346 }
07347 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07348 if ((newmsgs + oldmsgs) >= capacity) {
07349 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07350 res = ast_play_and_wait(chan, "vm-mailboxfull");
07351 valid_extensions = 0;
07352 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07353 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07354 free_user(vmtmp);
07355 }
07356 inprocess_count(receiver->mailbox, receiver->context, -1);
07357 break;
07358 }
07359 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07360 } else {
07361
07362
07363
07364
07365
07366 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07367 free_user(receiver);
07368 }
07369 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07370
07371 res = ast_play_and_wait(chan, "pbx-invalid");
07372 valid_extensions = 0;
07373 break;
07374 }
07375
07376
07377 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07378 RETRIEVE(fn, -1, s, receiver->context);
07379 if (ast_fileexists(fn, NULL, NULL) > 0) {
07380 res = ast_stream_and_wait(chan, fn, ecodes);
07381 if (res) {
07382 DISPOSE(fn, -1);
07383 return res;
07384 }
07385 } else {
07386 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07387 }
07388 DISPOSE(fn, -1);
07389
07390 s = strsep(&stringp, "*");
07391 }
07392
07393 if (valid_extensions)
07394 break;
07395 }
07396
07397 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07398 return res;
07399 if (is_new_message == 1) {
07400 struct leave_vm_options leave_options;
07401 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07402 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07403
07404
07405 memset(&leave_options, 0, sizeof(leave_options));
07406 leave_options.record_gain = record_gain;
07407 cmd = leave_voicemail(chan, mailbox, &leave_options);
07408 } else {
07409
07410 long duration = 0;
07411 struct vm_state vmstmp;
07412 int copy_msg_result = 0;
07413 memcpy(&vmstmp, vms, sizeof(vmstmp));
07414
07415 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07416
07417 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07418 if (!cmd) {
07419 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07420 #ifdef IMAP_STORAGE
07421 int attach_user_voicemail;
07422 char *myserveremail = serveremail;
07423
07424
07425 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07426 if (!dstvms) {
07427 dstvms = create_vm_state_from_user(vmtmp);
07428 }
07429 if (dstvms) {
07430 init_mailstream(dstvms, 0);
07431 if (!dstvms->mailstream) {
07432 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07433 } else {
07434 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07435 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07436 }
07437 } else {
07438 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07439 }
07440 if (!ast_strlen_zero(vmtmp->serveremail))
07441 myserveremail = vmtmp->serveremail;
07442 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07443
07444 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07445 dstvms->curbox,
07446 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07447 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07448 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07449 NULL, urgent_str);
07450 #else
07451 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07452 #endif
07453 saved_messages++;
07454 AST_LIST_REMOVE_CURRENT(list);
07455 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07456 free_user(vmtmp);
07457 if (res)
07458 break;
07459 }
07460 AST_LIST_TRAVERSE_SAFE_END;
07461 if (saved_messages > 0 && !copy_msg_result) {
07462
07463
07464
07465
07466
07467
07468
07469
07470 #ifdef IMAP_STORAGE
07471
07472 if (ast_strlen_zero(vmstmp.introfn))
07473 #endif
07474 res = ast_play_and_wait(chan, "vm-msgsaved");
07475 }
07476 #ifndef IMAP_STORAGE
07477 else {
07478
07479 res = ast_play_and_wait(chan, "vm-mailboxfull");
07480 }
07481
07482 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07483 strcpy(textfile, msgfile);
07484 strcpy(backup, msgfile);
07485 strcpy(backup_textfile, msgfile);
07486 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07487 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07488 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07489 if (ast_fileexists(backup, NULL, NULL) > 0) {
07490 ast_filerename(backup, msgfile, NULL);
07491 rename(backup_textfile, textfile);
07492 }
07493 #endif
07494 }
07495 DISPOSE(dir, curmsg);
07496 #ifndef IMAP_STORAGE
07497 if (cmd) {
07498 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07499 strcpy(textfile, msgfile);
07500 strcpy(backup_textfile, msgfile);
07501 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07502 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07503 rename(backup_textfile, textfile);
07504 }
07505 #endif
07506 }
07507
07508
07509 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07510 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07511 free_user(vmtmp);
07512 }
07513 return res ? res : cmd;
07514 }
07515
07516 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07517 {
07518 int res;
07519 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07520 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07521 return res;
07522 }
07523
07524 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07525 {
07526 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07527 return ast_control_streamfile(chan, file, listen_control_forward_key, listen_control_reverse_key, listen_control_stop_key, listen_control_pause_key, listen_control_restart_key, skipms, NULL);
07528 }
07529
07530 static int play_message_category(struct ast_channel *chan, const char *category)
07531 {
07532 int res = 0;
07533
07534 if (!ast_strlen_zero(category))
07535 res = ast_play_and_wait(chan, category);
07536
07537 if (res) {
07538 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07539 res = 0;
07540 }
07541
07542 return res;
07543 }
07544
07545 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07546 {
07547 int res = 0;
07548 struct vm_zone *the_zone = NULL;
07549 time_t t;
07550
07551 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07552 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07553 return 0;
07554 }
07555
07556
07557 if (!ast_strlen_zero(vmu->zonetag)) {
07558
07559 struct vm_zone *z;
07560 AST_LIST_LOCK(&zones);
07561 AST_LIST_TRAVERSE(&zones, z, list) {
07562 if (!strcmp(z->name, vmu->zonetag)) {
07563 the_zone = z;
07564 break;
07565 }
07566 }
07567 AST_LIST_UNLOCK(&zones);
07568 }
07569
07570
07571 #if 0
07572
07573 ast_localtime(&t, &time_now, NULL);
07574 tv_now = ast_tvnow();
07575 ast_localtime(&tv_now, &time_then, NULL);
07576
07577
07578 if (time_now.tm_year == time_then.tm_year)
07579 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07580 else
07581 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07582 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07583
07584
07585 #endif
07586 if (the_zone) {
07587 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07588 } else if (!strncasecmp(chan->language, "de", 2)) {
07589 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07590 } else if (!strncasecmp(chan->language, "gr", 2)) {
07591 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07592 } else if (!strncasecmp(chan->language, "it", 2)) {
07593 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
07594 } else if (!strncasecmp(chan->language, "nl", 2)) {
07595 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07596 } else if (!strncasecmp(chan->language, "no", 2)) {
07597 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07598 } else if (!strncasecmp(chan->language, "pl", 2)) {
07599 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07600 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07601 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL);
07602 } else if (!strncasecmp(chan->language, "se", 2)) {
07603 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07604 } else if (!strncasecmp(chan->language, "zh", 2)) {
07605 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07606 } else if (!strncasecmp(chan->language, "vi", 2)) {
07607 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' A 'digits/day' dB 'digits/year' Y 'digits/at' k 'hours' M 'minutes'", NULL);
07608 } else {
07609 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07610 }
07611 #if 0
07612 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07613 #endif
07614 return res;
07615 }
07616
07617
07618
07619 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07620 {
07621 int res = 0;
07622 int i;
07623 char *callerid, *name;
07624 char prefile[PATH_MAX] = "";
07625
07626
07627
07628
07629
07630
07631
07632
07633
07634 if ((cid == NULL)||(context == NULL))
07635 return res;
07636
07637
07638 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07639 ast_callerid_parse(cid, &name, &callerid);
07640 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07641
07642
07643 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07644 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07645 if ((strcmp(cidinternalcontexts[i], context) == 0))
07646 break;
07647 }
07648 if (i != MAX_NUM_CID_CONTEXTS){
07649 if (!res) {
07650 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07651 if (!ast_strlen_zero(prefile)) {
07652
07653 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07654 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07655 if (!callback)
07656 res = wait_file2(chan, vms, "vm-from");
07657 res = ast_stream_and_wait(chan, prefile, "");
07658 } else {
07659 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07660
07661 if (!callback)
07662 res = wait_file2(chan, vms, "vm-from-extension");
07663 res = ast_say_digit_str(chan, callerid, "", chan->language);
07664 }
07665 }
07666 }
07667 } else if (!res) {
07668 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07669
07670 if (!callback)
07671 res = wait_file2(chan, vms, "vm-from-phonenumber");
07672 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07673 }
07674 } else {
07675
07676 ast_debug(1, "VM-CID: From an unknown number\n");
07677
07678 res = wait_file2(chan, vms, "vm-unknown-caller");
07679 }
07680 return res;
07681 }
07682
07683 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07684 {
07685 int res = 0;
07686 int durationm;
07687 int durations;
07688
07689 if (duration == NULL)
07690 return res;
07691
07692
07693 durations = atoi(duration);
07694 durationm = (durations / 60);
07695
07696 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07697
07698 if ((!res) && (durationm >= minduration)) {
07699 res = wait_file2(chan, vms, "vm-duration");
07700
07701
07702 if (!strncasecmp(chan->language, "pl", 2)) {
07703 div_t num = div(durationm, 10);
07704
07705 if (durationm == 1) {
07706 res = ast_play_and_wait(chan, "digits/1z");
07707 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07708 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07709 if (num.rem == 2) {
07710 if (!num.quot) {
07711 res = ast_play_and_wait(chan, "digits/2-ie");
07712 } else {
07713 res = say_and_wait(chan, durationm - 2 , chan->language);
07714 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07715 }
07716 } else {
07717 res = say_and_wait(chan, durationm, chan->language);
07718 }
07719 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07720 } else {
07721 res = say_and_wait(chan, durationm, chan->language);
07722 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07723 }
07724
07725 } else {
07726 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07727 res = wait_file2(chan, vms, "vm-minutes");
07728 }
07729 }
07730 return res;
07731 }
07732
07733 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07734 {
07735 int res = 0;
07736 char filename[256], *cid;
07737 const char *origtime, *context, *category, *duration, *flag;
07738 struct ast_config *msg_cfg;
07739 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07740
07741 vms->starting = 0;
07742 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07743 adsi_message(chan, vms);
07744 if (!vms->curmsg) {
07745 res = wait_file2(chan, vms, "vm-first");
07746 } else if (vms->curmsg == vms->lastmsg) {
07747 res = wait_file2(chan, vms, "vm-last");
07748 }
07749
07750 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07751 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07752 msg_cfg = ast_config_load(filename, config_flags);
07753 if (!valid_config(msg_cfg)) {
07754 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07755 return 0;
07756 }
07757 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07758
07759
07760 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07761 res = wait_file2(chan, vms, "vm-Urgent");
07762 }
07763
07764 if (!res) {
07765
07766
07767 if (!strncasecmp(chan->language, "pl", 2)) {
07768 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07769 int ten, one;
07770 char nextmsg[256];
07771 ten = (vms->curmsg + 1) / 10;
07772 one = (vms->curmsg + 1) % 10;
07773
07774 if (vms->curmsg < 20) {
07775 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07776 res = wait_file2(chan, vms, nextmsg);
07777 } else {
07778 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07779 res = wait_file2(chan, vms, nextmsg);
07780 if (one > 0) {
07781 if (!res) {
07782 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07783 res = wait_file2(chan, vms, nextmsg);
07784 }
07785 }
07786 }
07787 }
07788 if (!res)
07789 res = wait_file2(chan, vms, "vm-message");
07790
07791 } else if (!strncasecmp(chan->language, "he", 2)) {
07792 if (!vms->curmsg) {
07793 res = wait_file2(chan, vms, "vm-message");
07794 res = wait_file2(chan, vms, "vm-first");
07795 } else if (vms->curmsg == vms->lastmsg) {
07796 res = wait_file2(chan, vms, "vm-message");
07797 res = wait_file2(chan, vms, "vm-last");
07798 } else {
07799 res = wait_file2(chan, vms, "vm-message");
07800 res = wait_file2(chan, vms, "vm-number");
07801 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07802 }
07803
07804 } else if (!strncasecmp(chan->language, "vi", 2)) {
07805 if (!vms->curmsg) {
07806 res = wait_file2(chan, vms, "vm-message");
07807 res = wait_file2(chan, vms, "vm-first");
07808 } else if (vms->curmsg == vms->lastmsg) {
07809 res = wait_file2(chan, vms, "vm-message");
07810 res = wait_file2(chan, vms, "vm-last");
07811 } else {
07812 res = wait_file2(chan, vms, "vm-message");
07813 res = wait_file2(chan, vms, "vm-number");
07814 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07815 }
07816 } else {
07817 if (!strncasecmp(chan->language, "se", 2)) {
07818 res = wait_file2(chan, vms, "vm-meddelandet");
07819 } else {
07820 res = wait_file2(chan, vms, "vm-message");
07821 }
07822 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07823 if (!res) {
07824 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07825 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07826 }
07827 }
07828 }
07829 }
07830
07831 if (!valid_config(msg_cfg)) {
07832 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07833 return 0;
07834 }
07835
07836 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07837 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07838 DISPOSE(vms->curdir, vms->curmsg);
07839 ast_config_destroy(msg_cfg);
07840 return 0;
07841 }
07842
07843 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07844 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07845 category = ast_variable_retrieve(msg_cfg, "message", "category");
07846
07847 context = ast_variable_retrieve(msg_cfg, "message", "context");
07848 if (!strncasecmp("macro", context, 5))
07849 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07850 if (!res) {
07851 res = play_message_category(chan, category);
07852 }
07853 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07854 res = play_message_datetime(chan, vmu, origtime, filename);
07855 }
07856 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07857 res = play_message_callerid(chan, vms, cid, context, 0);
07858 }
07859 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07860 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07861 }
07862
07863 if (res == '1') {
07864 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07865 res = 0;
07866 }
07867 ast_config_destroy(msg_cfg);
07868
07869 if (!res) {
07870 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07871 #ifdef IMAP_STORAGE
07872 ast_mutex_lock(&vms->lock);
07873 #endif
07874 vms->heard[vms->curmsg] = 1;
07875 #ifdef IMAP_STORAGE
07876 ast_mutex_unlock(&vms->lock);
07877
07878
07879
07880 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07881 wait_file(chan, vms, vms->introfn);
07882 }
07883 #endif
07884 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07885 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07886 res = 0;
07887 }
07888 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07889 }
07890 DISPOSE(vms->curdir, vms->curmsg);
07891 return res;
07892 }
07893
07894 #ifdef IMAP_STORAGE
07895 static int imap_remove_file(char *dir, int msgnum)
07896 {
07897 char fn[PATH_MAX];
07898 char full_fn[PATH_MAX];
07899 char intro[PATH_MAX] = {0,};
07900
07901 if (msgnum > -1) {
07902 make_file(fn, sizeof(fn), dir, msgnum);
07903 snprintf(intro, sizeof(intro), "%sintro", fn);
07904 } else
07905 ast_copy_string(fn, dir, sizeof(fn));
07906
07907 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07908 ast_filedelete(fn, NULL);
07909 if (!ast_strlen_zero(intro)) {
07910 ast_filedelete(intro, NULL);
07911 }
07912 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07913 unlink(full_fn);
07914 }
07915 return 0;
07916 }
07917
07918
07919
07920 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07921 {
07922 char *file, *filename;
07923 char *attachment;
07924 char arg[10];
07925 int i;
07926 BODY* body;
07927
07928 file = strrchr(ast_strdupa(dir), '/');
07929 if (file) {
07930 *file++ = '\0';
07931 } else {
07932 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07933 return -1;
07934 }
07935
07936 ast_mutex_lock(&vms->lock);
07937 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07938 mail_fetchstructure(vms->mailstream, i + 1, &body);
07939
07940 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07941 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07942 } else {
07943 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07944 ast_mutex_unlock(&vms->lock);
07945 return -1;
07946 }
07947 filename = strsep(&attachment, ".");
07948 if (!strcmp(filename, file)) {
07949 sprintf(arg, "%d", i + 1);
07950 mail_setflag(vms->mailstream, arg, "\\DELETED");
07951 }
07952 }
07953 mail_expunge(vms->mailstream);
07954 ast_mutex_unlock(&vms->lock);
07955 return 0;
07956 }
07957
07958 #elif !defined(IMAP_STORAGE)
07959 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07960 {
07961 int count_msg, last_msg;
07962
07963 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07964
07965
07966
07967
07968 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07969
07970
07971 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07972
07973
07974 count_msg = count_messages(vmu, vms->curdir);
07975 if (count_msg < 0) {
07976 return count_msg;
07977 } else {
07978 vms->lastmsg = count_msg - 1;
07979 }
07980
07981 if (vm_allocate_dh(vms, vmu, count_msg)) {
07982 return -1;
07983 }
07984
07985
07986
07987
07988
07989
07990
07991
07992 if (vm_lock_path(vms->curdir)) {
07993 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07994 return ERROR_LOCK_PATH;
07995 }
07996
07997
07998 last_msg = last_message_index(vmu, vms->curdir);
07999 ast_unlock_path(vms->curdir);
08000
08001 if (last_msg < -1) {
08002 return last_msg;
08003 } else if (vms->lastmsg != last_msg) {
08004 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
08005 resequence_mailbox(vmu, vms->curdir, count_msg);
08006 }
08007
08008 return 0;
08009 }
08010 #endif
08011
08012 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
08013 {
08014 int x = 0;
08015 int last_msg_idx = 0;
08016
08017 #ifndef IMAP_STORAGE
08018 int res = 0, nummsg;
08019 char fn2[PATH_MAX];
08020 #endif
08021
08022 if (vms->lastmsg <= -1) {
08023 goto done;
08024 }
08025
08026 vms->curmsg = -1;
08027 #ifndef IMAP_STORAGE
08028
08029 if (vm_lock_path(vms->curdir)) {
08030 return ERROR_LOCK_PATH;
08031 }
08032
08033
08034 last_msg_idx = last_message_index(vmu, vms->curdir);
08035 if (last_msg_idx != vms->lastmsg) {
08036 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
08037 }
08038
08039
08040 for (x = 0; x < last_msg_idx + 1; x++) {
08041 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
08042
08043 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08044 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
08045 break;
08046 }
08047 vms->curmsg++;
08048 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08049 if (strcmp(vms->fn, fn2)) {
08050 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08051 }
08052 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08053
08054 res = save_to_folder(vmu, vms, x, 1);
08055 if (res == ERROR_LOCK_PATH) {
08056
08057 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08058 vms->deleted[x] = 0;
08059 vms->heard[x] = 0;
08060 --x;
08061 }
08062 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08063
08064 res = save_to_folder(vmu, vms, x, 10);
08065 if (res == ERROR_LOCK_PATH) {
08066
08067 vms->deleted[x] = 0;
08068 vms->heard[x] = 0;
08069 --x;
08070 }
08071 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08072
08073
08074 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08075 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08076 DELETE(vms->curdir, x, vms->fn, vmu);
08077 }
08078 }
08079 }
08080
08081
08082 nummsg = x - 1;
08083 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08084 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08085 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08086 DELETE(vms->curdir, x, vms->fn, vmu);
08087 }
08088 }
08089 ast_unlock_path(vms->curdir);
08090 #else
08091 ast_mutex_lock(&vms->lock);
08092 if (vms->deleted) {
08093
08094
08095 last_msg_idx = vms->dh_arraysize;
08096 for (x = last_msg_idx - 1; x >= 0; x--) {
08097 if (vms->deleted[x]) {
08098 ast_debug(3, "IMAP delete of %d\n", x);
08099 DELETE(vms->curdir, x, vms->fn, vmu);
08100 }
08101 }
08102 }
08103 #endif
08104
08105 done:
08106 if (vms->deleted) {
08107 ast_free(vms->deleted);
08108 vms->deleted = NULL;
08109 }
08110 if (vms->heard) {
08111 ast_free(vms->heard);
08112 vms->heard = NULL;
08113 }
08114 vms->dh_arraysize = 0;
08115 #ifdef IMAP_STORAGE
08116 ast_mutex_unlock(&vms->lock);
08117 #endif
08118
08119 return 0;
08120 }
08121
08122
08123
08124
08125
08126
08127
08128 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08129 {
08130 int cmd;
08131 char *buf;
08132
08133 buf = ast_alloca(strlen(box) + 2);
08134 strcpy(buf, box);
08135 strcat(buf, "s");
08136
08137 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08138 cmd = ast_play_and_wait(chan, buf);
08139 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08140 } else {
08141 cmd = ast_play_and_wait(chan, "vm-messages");
08142 return cmd ? cmd : ast_play_and_wait(chan, box);
08143 }
08144 }
08145
08146 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08147 {
08148 int cmd;
08149
08150 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08151 if (!strcasecmp(box, "vm-INBOX"))
08152 cmd = ast_play_and_wait(chan, "vm-new-e");
08153 else
08154 cmd = ast_play_and_wait(chan, "vm-old-e");
08155 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08156 } else {
08157 cmd = ast_play_and_wait(chan, "vm-messages");
08158 return cmd ? cmd : ast_play_and_wait(chan, box);
08159 }
08160 }
08161
08162 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08163 {
08164 int cmd;
08165
08166 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08167 cmd = ast_play_and_wait(chan, "vm-messages");
08168 return cmd ? cmd : ast_play_and_wait(chan, box);
08169 } else {
08170 cmd = ast_play_and_wait(chan, box);
08171 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08172 }
08173 }
08174
08175 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08176 {
08177 int cmd;
08178
08179 if ( !strncasecmp(chan->language, "it", 2) ||
08180 !strncasecmp(chan->language, "es", 2) ||
08181 !strncasecmp(chan->language, "pt", 2)) {
08182 cmd = ast_play_and_wait(chan, "vm-messages");
08183 return cmd ? cmd : ast_play_and_wait(chan, box);
08184 } else if (!strncasecmp(chan->language, "gr", 2)) {
08185 return vm_play_folder_name_gr(chan, box);
08186 } else if (!strncasecmp(chan->language, "he", 2)) {
08187 return ast_play_and_wait(chan, box);
08188 } else if (!strncasecmp(chan->language, "pl", 2)) {
08189 return vm_play_folder_name_pl(chan, box);
08190 } else if (!strncasecmp(chan->language, "ua", 2)) {
08191 return vm_play_folder_name_ua(chan, box);
08192 } else if (!strncasecmp(chan->language, "vi", 2)) {
08193 return ast_play_and_wait(chan, box);
08194 } else {
08195 cmd = ast_play_and_wait(chan, box);
08196 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08197 }
08198 }
08199
08200
08201
08202
08203
08204
08205
08206
08207
08208
08209
08210
08211
08212 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08213 {
08214 int res = 0;
08215
08216 if (vms->newmessages) {
08217 res = ast_play_and_wait(chan, "vm-youhave");
08218 if (!res)
08219 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08220 if (!res) {
08221 if ((vms->newmessages == 1)) {
08222 res = ast_play_and_wait(chan, "vm-INBOX");
08223 if (!res)
08224 res = ast_play_and_wait(chan, "vm-message");
08225 } else {
08226 res = ast_play_and_wait(chan, "vm-INBOXs");
08227 if (!res)
08228 res = ast_play_and_wait(chan, "vm-messages");
08229 }
08230 }
08231 } else if (vms->oldmessages){
08232 res = ast_play_and_wait(chan, "vm-youhave");
08233 if (!res)
08234 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08235 if ((vms->oldmessages == 1)){
08236 res = ast_play_and_wait(chan, "vm-Old");
08237 if (!res)
08238 res = ast_play_and_wait(chan, "vm-message");
08239 } else {
08240 res = ast_play_and_wait(chan, "vm-Olds");
08241 if (!res)
08242 res = ast_play_and_wait(chan, "vm-messages");
08243 }
08244 } else if (!vms->oldmessages && !vms->newmessages)
08245 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08246 return res;
08247 }
08248
08249
08250
08251
08252
08253
08254
08255
08256
08257
08258
08259
08260
08261
08262
08263
08264
08265
08266
08267
08268
08269
08270
08271
08272
08273
08274
08275
08276
08277
08278
08279
08280
08281
08282
08283
08284
08285
08286
08287
08288
08289
08290
08291
08292
08293
08294
08295
08296
08297
08298
08299
08300
08301
08302
08303
08304
08305
08306 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08307 {
08308 int res;
08309 int lastnum = 0;
08310
08311 res = ast_play_and_wait(chan, "vm-youhave");
08312
08313 if (!res && vms->newmessages) {
08314 lastnum = vms->newmessages;
08315
08316 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08317 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08318 }
08319
08320 if (!res && vms->oldmessages) {
08321 res = ast_play_and_wait(chan, "vm-and");
08322 }
08323 }
08324
08325 if (!res && vms->oldmessages) {
08326 lastnum = vms->oldmessages;
08327
08328 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08329 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08330 }
08331 }
08332
08333 if (!res) {
08334 if (lastnum == 0) {
08335 res = ast_play_and_wait(chan, "vm-no");
08336 }
08337 if (!res) {
08338 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08339 }
08340 }
08341
08342 return res;
08343 }
08344
08345
08346 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08347 {
08348 int res = 0;
08349
08350
08351 if (!res) {
08352 if ((vms->newmessages) || (vms->oldmessages)) {
08353 res = ast_play_and_wait(chan, "vm-youhave");
08354 }
08355
08356
08357
08358
08359
08360 if (vms->newmessages) {
08361 if (!res) {
08362 if (vms->newmessages == 1) {
08363 res = ast_play_and_wait(chan, "vm-INBOX1");
08364 } else {
08365 if (vms->newmessages == 2) {
08366 res = ast_play_and_wait(chan, "vm-shtei");
08367 } else {
08368 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08369 }
08370 res = ast_play_and_wait(chan, "vm-INBOX");
08371 }
08372 }
08373 if (vms->oldmessages && !res) {
08374 res = ast_play_and_wait(chan, "vm-and");
08375 if (vms->oldmessages == 1) {
08376 res = ast_play_and_wait(chan, "vm-Old1");
08377 } else {
08378 if (vms->oldmessages == 2) {
08379 res = ast_play_and_wait(chan, "vm-shtei");
08380 } else {
08381 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08382 }
08383 res = ast_play_and_wait(chan, "vm-Old");
08384 }
08385 }
08386 }
08387 if (!res && vms->oldmessages && !vms->newmessages) {
08388 if (!res) {
08389 if (vms->oldmessages == 1) {
08390 res = ast_play_and_wait(chan, "vm-Old1");
08391 } else {
08392 if (vms->oldmessages == 2) {
08393 res = ast_play_and_wait(chan, "vm-shtei");
08394 } else {
08395 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08396 }
08397 res = ast_play_and_wait(chan, "vm-Old");
08398 }
08399 }
08400 }
08401 if (!res) {
08402 if (!vms->oldmessages && !vms->newmessages) {
08403 if (!res) {
08404 res = ast_play_and_wait(chan, "vm-nomessages");
08405 }
08406 }
08407 }
08408 }
08409 return res;
08410 }
08411
08412
08413 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08414 {
08415 int res;
08416
08417
08418 res = ast_play_and_wait(chan, "vm-youhave");
08419 if (!res) {
08420 if (vms->urgentmessages) {
08421 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08422 if (!res)
08423 res = ast_play_and_wait(chan, "vm-Urgent");
08424 if ((vms->oldmessages || vms->newmessages) && !res) {
08425 res = ast_play_and_wait(chan, "vm-and");
08426 } else if (!res) {
08427 if ((vms->urgentmessages == 1))
08428 res = ast_play_and_wait(chan, "vm-message");
08429 else
08430 res = ast_play_and_wait(chan, "vm-messages");
08431 }
08432 }
08433 if (vms->newmessages) {
08434 res = say_and_wait(chan, vms->newmessages, chan->language);
08435 if (!res)
08436 res = ast_play_and_wait(chan, "vm-INBOX");
08437 if (vms->oldmessages && !res)
08438 res = ast_play_and_wait(chan, "vm-and");
08439 else if (!res) {
08440 if ((vms->newmessages == 1))
08441 res = ast_play_and_wait(chan, "vm-message");
08442 else
08443 res = ast_play_and_wait(chan, "vm-messages");
08444 }
08445
08446 }
08447 if (!res && vms->oldmessages) {
08448 res = say_and_wait(chan, vms->oldmessages, chan->language);
08449 if (!res)
08450 res = ast_play_and_wait(chan, "vm-Old");
08451 if (!res) {
08452 if (vms->oldmessages == 1)
08453 res = ast_play_and_wait(chan, "vm-message");
08454 else
08455 res = ast_play_and_wait(chan, "vm-messages");
08456 }
08457 }
08458 if (!res) {
08459 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08460 res = ast_play_and_wait(chan, "vm-no");
08461 if (!res)
08462 res = ast_play_and_wait(chan, "vm-messages");
08463 }
08464 }
08465 }
08466 return res;
08467 }
08468
08469
08470 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08471 {
08472
08473 int res;
08474 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08475 res = ast_play_and_wait(chan, "vm-no") ||
08476 ast_play_and_wait(chan, "vm-message");
08477 else
08478 res = ast_play_and_wait(chan, "vm-youhave");
08479 if (!res && vms->newmessages) {
08480 res = (vms->newmessages == 1) ?
08481 ast_play_and_wait(chan, "digits/un") ||
08482 ast_play_and_wait(chan, "vm-nuovo") ||
08483 ast_play_and_wait(chan, "vm-message") :
08484
08485 say_and_wait(chan, vms->newmessages, chan->language) ||
08486 ast_play_and_wait(chan, "vm-nuovi") ||
08487 ast_play_and_wait(chan, "vm-messages");
08488 if (!res && vms->oldmessages)
08489 res = ast_play_and_wait(chan, "vm-and");
08490 }
08491 if (!res && vms->oldmessages) {
08492 res = (vms->oldmessages == 1) ?
08493 ast_play_and_wait(chan, "digits/un") ||
08494 ast_play_and_wait(chan, "vm-vecchio") ||
08495 ast_play_and_wait(chan, "vm-message") :
08496
08497 say_and_wait(chan, vms->oldmessages, chan->language) ||
08498 ast_play_and_wait(chan, "vm-vecchi") ||
08499 ast_play_and_wait(chan, "vm-messages");
08500 }
08501 return res;
08502 }
08503
08504
08505 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08506 {
08507
08508 int res;
08509 div_t num;
08510
08511 if (!vms->oldmessages && !vms->newmessages) {
08512 res = ast_play_and_wait(chan, "vm-no");
08513 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08514 return res;
08515 } else {
08516 res = ast_play_and_wait(chan, "vm-youhave");
08517 }
08518
08519 if (vms->newmessages) {
08520 num = div(vms->newmessages, 10);
08521 if (vms->newmessages == 1) {
08522 res = ast_play_and_wait(chan, "digits/1-a");
08523 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08524 res = res ? res : ast_play_and_wait(chan, "vm-message");
08525 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08526 if (num.rem == 2) {
08527 if (!num.quot) {
08528 res = ast_play_and_wait(chan, "digits/2-ie");
08529 } else {
08530 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08531 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08532 }
08533 } else {
08534 res = say_and_wait(chan, vms->newmessages, chan->language);
08535 }
08536 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08537 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08538 } else {
08539 res = say_and_wait(chan, vms->newmessages, chan->language);
08540 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08541 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08542 }
08543 if (!res && vms->oldmessages)
08544 res = ast_play_and_wait(chan, "vm-and");
08545 }
08546 if (!res && vms->oldmessages) {
08547 num = div(vms->oldmessages, 10);
08548 if (vms->oldmessages == 1) {
08549 res = ast_play_and_wait(chan, "digits/1-a");
08550 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08551 res = res ? res : ast_play_and_wait(chan, "vm-message");
08552 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08553 if (num.rem == 2) {
08554 if (!num.quot) {
08555 res = ast_play_and_wait(chan, "digits/2-ie");
08556 } else {
08557 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08558 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08559 }
08560 } else {
08561 res = say_and_wait(chan, vms->oldmessages, chan->language);
08562 }
08563 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08564 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08565 } else {
08566 res = say_and_wait(chan, vms->oldmessages, chan->language);
08567 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08568 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08569 }
08570 }
08571
08572 return res;
08573 }
08574
08575
08576 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08577 {
08578
08579 int res;
08580
08581 res = ast_play_and_wait(chan, "vm-youhave");
08582 if (res)
08583 return res;
08584
08585 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08586 res = ast_play_and_wait(chan, "vm-no");
08587 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08588 return res;
08589 }
08590
08591 if (vms->newmessages) {
08592 if ((vms->newmessages == 1)) {
08593 res = ast_play_and_wait(chan, "digits/ett");
08594 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08595 res = res ? res : ast_play_and_wait(chan, "vm-message");
08596 } else {
08597 res = say_and_wait(chan, vms->newmessages, chan->language);
08598 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08599 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08600 }
08601 if (!res && vms->oldmessages)
08602 res = ast_play_and_wait(chan, "vm-and");
08603 }
08604 if (!res && vms->oldmessages) {
08605 if (vms->oldmessages == 1) {
08606 res = ast_play_and_wait(chan, "digits/ett");
08607 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08608 res = res ? res : ast_play_and_wait(chan, "vm-message");
08609 } else {
08610 res = say_and_wait(chan, vms->oldmessages, chan->language);
08611 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08612 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08613 }
08614 }
08615
08616 return res;
08617 }
08618
08619
08620 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08621 {
08622
08623 int res;
08624
08625 res = ast_play_and_wait(chan, "vm-youhave");
08626 if (res)
08627 return res;
08628
08629 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08630 res = ast_play_and_wait(chan, "vm-no");
08631 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08632 return res;
08633 }
08634
08635 if (vms->newmessages) {
08636 if ((vms->newmessages == 1)) {
08637 res = ast_play_and_wait(chan, "digits/1");
08638 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08639 res = res ? res : ast_play_and_wait(chan, "vm-message");
08640 } else {
08641 res = say_and_wait(chan, vms->newmessages, chan->language);
08642 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08643 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08644 }
08645 if (!res && vms->oldmessages)
08646 res = ast_play_and_wait(chan, "vm-and");
08647 }
08648 if (!res && vms->oldmessages) {
08649 if (vms->oldmessages == 1) {
08650 res = ast_play_and_wait(chan, "digits/1");
08651 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08652 res = res ? res : ast_play_and_wait(chan, "vm-message");
08653 } else {
08654 res = say_and_wait(chan, vms->oldmessages, chan->language);
08655 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08656 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08657 }
08658 }
08659
08660 return res;
08661 }
08662
08663
08664 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08665 {
08666
08667 int res;
08668 res = ast_play_and_wait(chan, "vm-youhave");
08669 if (!res) {
08670 if (vms->newmessages) {
08671 if ((vms->newmessages == 1))
08672 res = ast_play_and_wait(chan, "digits/1F");
08673 else
08674 res = say_and_wait(chan, vms->newmessages, chan->language);
08675 if (!res)
08676 res = ast_play_and_wait(chan, "vm-INBOX");
08677 if (vms->oldmessages && !res)
08678 res = ast_play_and_wait(chan, "vm-and");
08679 else if (!res) {
08680 if ((vms->newmessages == 1))
08681 res = ast_play_and_wait(chan, "vm-message");
08682 else
08683 res = ast_play_and_wait(chan, "vm-messages");
08684 }
08685
08686 }
08687 if (!res && vms->oldmessages) {
08688 if (vms->oldmessages == 1)
08689 res = ast_play_and_wait(chan, "digits/1F");
08690 else
08691 res = say_and_wait(chan, vms->oldmessages, chan->language);
08692 if (!res)
08693 res = ast_play_and_wait(chan, "vm-Old");
08694 if (!res) {
08695 if (vms->oldmessages == 1)
08696 res = ast_play_and_wait(chan, "vm-message");
08697 else
08698 res = ast_play_and_wait(chan, "vm-messages");
08699 }
08700 }
08701 if (!res) {
08702 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08703 res = ast_play_and_wait(chan, "vm-no");
08704 if (!res)
08705 res = ast_play_and_wait(chan, "vm-messages");
08706 }
08707 }
08708 }
08709 return res;
08710 }
08711
08712
08713 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08714 {
08715
08716 int res;
08717 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08718 res = ast_play_and_wait(chan, "vm-youhaveno");
08719 if (!res)
08720 res = ast_play_and_wait(chan, "vm-messages");
08721 } else {
08722 res = ast_play_and_wait(chan, "vm-youhave");
08723 }
08724 if (!res) {
08725 if (vms->newmessages) {
08726 if (!res) {
08727 if ((vms->newmessages == 1)) {
08728 res = ast_play_and_wait(chan, "digits/1");
08729 if (!res)
08730 res = ast_play_and_wait(chan, "vm-message");
08731 if (!res)
08732 res = ast_play_and_wait(chan, "vm-INBOXs");
08733 } else {
08734 res = say_and_wait(chan, vms->newmessages, chan->language);
08735 if (!res)
08736 res = ast_play_and_wait(chan, "vm-messages");
08737 if (!res)
08738 res = ast_play_and_wait(chan, "vm-INBOX");
08739 }
08740 }
08741 if (vms->oldmessages && !res)
08742 res = ast_play_and_wait(chan, "vm-and");
08743 }
08744 if (vms->oldmessages) {
08745 if (!res) {
08746 if (vms->oldmessages == 1) {
08747 res = ast_play_and_wait(chan, "digits/1");
08748 if (!res)
08749 res = ast_play_and_wait(chan, "vm-message");
08750 if (!res)
08751 res = ast_play_and_wait(chan, "vm-Olds");
08752 } else {
08753 res = say_and_wait(chan, vms->oldmessages, chan->language);
08754 if (!res)
08755 res = ast_play_and_wait(chan, "vm-messages");
08756 if (!res)
08757 res = ast_play_and_wait(chan, "vm-Old");
08758 }
08759 }
08760 }
08761 }
08762 return res;
08763 }
08764
08765
08766 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08767
08768 int res;
08769 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08770 res = ast_play_and_wait(chan, "vm-nomessages");
08771 return res;
08772 } else {
08773 res = ast_play_and_wait(chan, "vm-youhave");
08774 }
08775 if (vms->newmessages) {
08776 if (!res)
08777 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08778 if ((vms->newmessages == 1)) {
08779 if (!res)
08780 res = ast_play_and_wait(chan, "vm-message");
08781 if (!res)
08782 res = ast_play_and_wait(chan, "vm-INBOXs");
08783 } else {
08784 if (!res)
08785 res = ast_play_and_wait(chan, "vm-messages");
08786 if (!res)
08787 res = ast_play_and_wait(chan, "vm-INBOX");
08788 }
08789 if (vms->oldmessages && !res)
08790 res = ast_play_and_wait(chan, "vm-and");
08791 }
08792 if (vms->oldmessages) {
08793 if (!res)
08794 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08795 if (vms->oldmessages == 1) {
08796 if (!res)
08797 res = ast_play_and_wait(chan, "vm-message");
08798 if (!res)
08799 res = ast_play_and_wait(chan, "vm-Olds");
08800 } else {
08801 if (!res)
08802 res = ast_play_and_wait(chan, "vm-messages");
08803 if (!res)
08804 res = ast_play_and_wait(chan, "vm-Old");
08805 }
08806 }
08807 return res;
08808 }
08809
08810
08811 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08812 {
08813
08814 int res;
08815 res = ast_play_and_wait(chan, "vm-youhave");
08816 if (!res) {
08817 if (vms->newmessages) {
08818 res = say_and_wait(chan, vms->newmessages, chan->language);
08819 if (!res)
08820 res = ast_play_and_wait(chan, "vm-INBOX");
08821 if (vms->oldmessages && !res)
08822 res = ast_play_and_wait(chan, "vm-and");
08823 else if (!res) {
08824 if ((vms->newmessages == 1))
08825 res = ast_play_and_wait(chan, "vm-message");
08826 else
08827 res = ast_play_and_wait(chan, "vm-messages");
08828 }
08829
08830 }
08831 if (!res && vms->oldmessages) {
08832 res = say_and_wait(chan, vms->oldmessages, chan->language);
08833 if (!res)
08834 res = ast_play_and_wait(chan, "vm-Old");
08835 if (!res) {
08836 if (vms->oldmessages == 1)
08837 res = ast_play_and_wait(chan, "vm-message");
08838 else
08839 res = ast_play_and_wait(chan, "vm-messages");
08840 }
08841 }
08842 if (!res) {
08843 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08844 res = ast_play_and_wait(chan, "vm-no");
08845 if (!res)
08846 res = ast_play_and_wait(chan, "vm-messages");
08847 }
08848 }
08849 }
08850 return res;
08851 }
08852
08853
08854 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08855 {
08856
08857 int res;
08858 res = ast_play_and_wait(chan, "vm-youhave");
08859 if (!res) {
08860 if (vms->newmessages) {
08861 res = say_and_wait(chan, vms->newmessages, chan->language);
08862 if (!res) {
08863 if (vms->newmessages == 1)
08864 res = ast_play_and_wait(chan, "vm-INBOXs");
08865 else
08866 res = ast_play_and_wait(chan, "vm-INBOX");
08867 }
08868 if (vms->oldmessages && !res)
08869 res = ast_play_and_wait(chan, "vm-and");
08870 else if (!res) {
08871 if ((vms->newmessages == 1))
08872 res = ast_play_and_wait(chan, "vm-message");
08873 else
08874 res = ast_play_and_wait(chan, "vm-messages");
08875 }
08876
08877 }
08878 if (!res && vms->oldmessages) {
08879 res = say_and_wait(chan, vms->oldmessages, chan->language);
08880 if (!res) {
08881 if (vms->oldmessages == 1)
08882 res = ast_play_and_wait(chan, "vm-Olds");
08883 else
08884 res = ast_play_and_wait(chan, "vm-Old");
08885 }
08886 if (!res) {
08887 if (vms->oldmessages == 1)
08888 res = ast_play_and_wait(chan, "vm-message");
08889 else
08890 res = ast_play_and_wait(chan, "vm-messages");
08891 }
08892 }
08893 if (!res) {
08894 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08895 res = ast_play_and_wait(chan, "vm-no");
08896 if (!res)
08897 res = ast_play_and_wait(chan, "vm-messages");
08898 }
08899 }
08900 }
08901 return res;
08902 }
08903
08904
08905 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08906 {
08907
08908 int res;
08909 res = ast_play_and_wait(chan, "vm-youhave");
08910 if (!res) {
08911 if (vms->newmessages) {
08912 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08913 if (!res) {
08914 if ((vms->newmessages == 1)) {
08915 res = ast_play_and_wait(chan, "vm-message");
08916 if (!res)
08917 res = ast_play_and_wait(chan, "vm-INBOXs");
08918 } else {
08919 res = ast_play_and_wait(chan, "vm-messages");
08920 if (!res)
08921 res = ast_play_and_wait(chan, "vm-INBOX");
08922 }
08923 }
08924 if (vms->oldmessages && !res)
08925 res = ast_play_and_wait(chan, "vm-and");
08926 }
08927 if (!res && vms->oldmessages) {
08928 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08929 if (!res) {
08930 if (vms->oldmessages == 1) {
08931 res = ast_play_and_wait(chan, "vm-message");
08932 if (!res)
08933 res = ast_play_and_wait(chan, "vm-Olds");
08934 } else {
08935 res = ast_play_and_wait(chan, "vm-messages");
08936 if (!res)
08937 res = ast_play_and_wait(chan, "vm-Old");
08938 }
08939 }
08940 }
08941 if (!res) {
08942 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08943 res = ast_play_and_wait(chan, "vm-no");
08944 if (!res)
08945 res = ast_play_and_wait(chan, "vm-messages");
08946 }
08947 }
08948 }
08949 return res;
08950 }
08951
08952
08953
08954
08955
08956
08957
08958
08959
08960
08961
08962
08963
08964
08965
08966
08967
08968 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08969 {
08970 int res;
08971 res = ast_play_and_wait(chan, "vm-youhave");
08972 if (!res) {
08973 if (vms->newmessages) {
08974 if (vms->newmessages == 1) {
08975 res = ast_play_and_wait(chan, "digits/jednu");
08976 } else {
08977 res = say_and_wait(chan, vms->newmessages, chan->language);
08978 }
08979 if (!res) {
08980 if ((vms->newmessages == 1))
08981 res = ast_play_and_wait(chan, "vm-novou");
08982 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08983 res = ast_play_and_wait(chan, "vm-nove");
08984 if (vms->newmessages > 4)
08985 res = ast_play_and_wait(chan, "vm-novych");
08986 }
08987 if (vms->oldmessages && !res)
08988 res = ast_play_and_wait(chan, "vm-and");
08989 else if (!res) {
08990 if ((vms->newmessages == 1))
08991 res = ast_play_and_wait(chan, "vm-zpravu");
08992 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08993 res = ast_play_and_wait(chan, "vm-zpravy");
08994 if (vms->newmessages > 4)
08995 res = ast_play_and_wait(chan, "vm-zprav");
08996 }
08997 }
08998 if (!res && vms->oldmessages) {
08999 res = say_and_wait(chan, vms->oldmessages, chan->language);
09000 if (!res) {
09001 if ((vms->oldmessages == 1))
09002 res = ast_play_and_wait(chan, "vm-starou");
09003 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
09004 res = ast_play_and_wait(chan, "vm-stare");
09005 if (vms->oldmessages > 4)
09006 res = ast_play_and_wait(chan, "vm-starych");
09007 }
09008 if (!res) {
09009 if ((vms->oldmessages == 1))
09010 res = ast_play_and_wait(chan, "vm-zpravu");
09011 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
09012 res = ast_play_and_wait(chan, "vm-zpravy");
09013 if (vms->oldmessages > 4)
09014 res = ast_play_and_wait(chan, "vm-zprav");
09015 }
09016 }
09017 if (!res) {
09018 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09019 res = ast_play_and_wait(chan, "vm-no");
09020 if (!res)
09021 res = ast_play_and_wait(chan, "vm-zpravy");
09022 }
09023 }
09024 }
09025 return res;
09026 }
09027
09028
09029 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
09030 {
09031 int res;
09032
09033 res = ast_play_and_wait(chan, "vm-you");
09034
09035 if (!res && vms->newmessages) {
09036 res = ast_play_and_wait(chan, "vm-have");
09037 if (!res)
09038 res = say_and_wait(chan, vms->newmessages, chan->language);
09039 if (!res)
09040 res = ast_play_and_wait(chan, "vm-tong");
09041 if (!res)
09042 res = ast_play_and_wait(chan, "vm-INBOX");
09043 if (vms->oldmessages && !res)
09044 res = ast_play_and_wait(chan, "vm-and");
09045 else if (!res)
09046 res = ast_play_and_wait(chan, "vm-messages");
09047 }
09048 if (!res && vms->oldmessages) {
09049 res = ast_play_and_wait(chan, "vm-have");
09050 if (!res)
09051 res = say_and_wait(chan, vms->oldmessages, chan->language);
09052 if (!res)
09053 res = ast_play_and_wait(chan, "vm-tong");
09054 if (!res)
09055 res = ast_play_and_wait(chan, "vm-Old");
09056 if (!res)
09057 res = ast_play_and_wait(chan, "vm-messages");
09058 }
09059 if (!res && !vms->oldmessages && !vms->newmessages) {
09060 res = ast_play_and_wait(chan, "vm-haveno");
09061 if (!res)
09062 res = ast_play_and_wait(chan, "vm-messages");
09063 }
09064 return res;
09065 }
09066
09067
09068 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09069 {
09070 int res;
09071
09072
09073 res = ast_play_and_wait(chan, "vm-youhave");
09074 if (!res) {
09075 if (vms->newmessages) {
09076 res = say_and_wait(chan, vms->newmessages, chan->language);
09077 if (!res)
09078 res = ast_play_and_wait(chan, "vm-INBOX");
09079 if (vms->oldmessages && !res)
09080 res = ast_play_and_wait(chan, "vm-and");
09081 }
09082 if (!res && vms->oldmessages) {
09083 res = say_and_wait(chan, vms->oldmessages, chan->language);
09084 if (!res)
09085 res = ast_play_and_wait(chan, "vm-Old");
09086 }
09087 if (!res) {
09088 if (!vms->oldmessages && !vms->newmessages) {
09089 res = ast_play_and_wait(chan, "vm-no");
09090 if (!res)
09091 res = ast_play_and_wait(chan, "vm-message");
09092 }
09093 }
09094 }
09095 return res;
09096 }
09097
09098 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09099 {
09100 char prefile[256];
09101
09102
09103 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09104 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09105 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09106 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09107 ast_play_and_wait(chan, "vm-tempgreetactive");
09108 }
09109 DISPOSE(prefile, -1);
09110 }
09111
09112
09113 if (0) {
09114 return 0;
09115 } else if (!strncasecmp(chan->language, "cs", 2)) {
09116 return vm_intro_cs(chan, vms);
09117 } else if (!strncasecmp(chan->language, "cz", 2)) {
09118 static int deprecation_warning = 0;
09119 if (deprecation_warning++ % 10 == 0) {
09120 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09121 }
09122 return vm_intro_cs(chan, vms);
09123 } else if (!strncasecmp(chan->language, "de", 2)) {
09124 return vm_intro_de(chan, vms);
09125 } else if (!strncasecmp(chan->language, "es", 2)) {
09126 return vm_intro_es(chan, vms);
09127 } else if (!strncasecmp(chan->language, "fr", 2)) {
09128 return vm_intro_fr(chan, vms);
09129 } else if (!strncasecmp(chan->language, "gr", 2)) {
09130 return vm_intro_gr(chan, vms);
09131 } else if (!strncasecmp(chan->language, "he", 2)) {
09132 return vm_intro_he(chan, vms);
09133 } else if (!strncasecmp(chan->language, "it", 2)) {
09134 return vm_intro_it(chan, vms);
09135 } else if (!strncasecmp(chan->language, "nl", 2)) {
09136 return vm_intro_nl(chan, vms);
09137 } else if (!strncasecmp(chan->language, "no", 2)) {
09138 return vm_intro_no(chan, vms);
09139 } else if (!strncasecmp(chan->language, "pl", 2)) {
09140 return vm_intro_pl(chan, vms);
09141 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09142 return vm_intro_pt_BR(chan, vms);
09143 } else if (!strncasecmp(chan->language, "pt", 2)) {
09144 return vm_intro_pt(chan, vms);
09145 } else if (!strncasecmp(chan->language, "ru", 2)) {
09146 return vm_intro_multilang(chan, vms, "n");
09147 } else if (!strncasecmp(chan->language, "se", 2)) {
09148 return vm_intro_se(chan, vms);
09149 } else if (!strncasecmp(chan->language, "ua", 2)) {
09150 return vm_intro_multilang(chan, vms, "n");
09151 } else if (!strncasecmp(chan->language, "vi", 2)) {
09152 return vm_intro_vi(chan, vms);
09153 } else if (!strncasecmp(chan->language, "zh", 2)) {
09154 return vm_intro_zh(chan, vms);
09155 } else {
09156 return vm_intro_en(chan, vms);
09157 }
09158 }
09159
09160 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09161 {
09162 int res = 0;
09163
09164 while (!res) {
09165 if (vms->starting) {
09166 if (vms->lastmsg > -1) {
09167 if (skipadvanced)
09168 res = ast_play_and_wait(chan, "vm-onefor-full");
09169 else
09170 res = ast_play_and_wait(chan, "vm-onefor");
09171 if (!res)
09172 res = vm_play_folder_name(chan, vms->vmbox);
09173 }
09174 if (!res) {
09175 if (skipadvanced)
09176 res = ast_play_and_wait(chan, "vm-opts-full");
09177 else
09178 res = ast_play_and_wait(chan, "vm-opts");
09179 }
09180 } else {
09181
09182 if (skipadvanced) {
09183 res = ast_play_and_wait(chan, "vm-onefor-full");
09184 if (!res)
09185 res = vm_play_folder_name(chan, vms->vmbox);
09186 res = ast_play_and_wait(chan, "vm-opts-full");
09187 }
09188
09189
09190
09191
09192
09193
09194 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09195 res = ast_play_and_wait(chan, "vm-prev");
09196 }
09197 if (!res && !skipadvanced)
09198 res = ast_play_and_wait(chan, "vm-advopts");
09199 if (!res)
09200 res = ast_play_and_wait(chan, "vm-repeat");
09201
09202
09203
09204
09205
09206
09207 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09208 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09209 res = ast_play_and_wait(chan, "vm-next");
09210 }
09211 if (!res) {
09212 int curmsg_deleted;
09213 #ifdef IMAP_STORAGE
09214 ast_mutex_lock(&vms->lock);
09215 #endif
09216 curmsg_deleted = vms->deleted[vms->curmsg];
09217 #ifdef IMAP_STORAGE
09218 ast_mutex_unlock(&vms->lock);
09219 #endif
09220 if (!curmsg_deleted) {
09221 res = ast_play_and_wait(chan, "vm-delete");
09222 } else {
09223 res = ast_play_and_wait(chan, "vm-undelete");
09224 }
09225 if (!res) {
09226 res = ast_play_and_wait(chan, "vm-toforward");
09227 }
09228 if (!res) {
09229 res = ast_play_and_wait(chan, "vm-savemessage");
09230 }
09231 }
09232 }
09233 if (!res) {
09234 res = ast_play_and_wait(chan, "vm-helpexit");
09235 }
09236 if (!res)
09237 res = ast_waitfordigit(chan, 6000);
09238 if (!res) {
09239 vms->repeats++;
09240 if (vms->repeats > 2) {
09241 res = 't';
09242 }
09243 }
09244 }
09245 return res;
09246 }
09247
09248 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09249 {
09250 int res = 0;
09251
09252 while (!res) {
09253 if (vms->lastmsg > -1) {
09254 res = ast_play_and_wait(chan, "vm-listen");
09255 if (!res)
09256 res = vm_play_folder_name(chan, vms->vmbox);
09257 if (!res)
09258 res = ast_play_and_wait(chan, "press");
09259 if (!res)
09260 res = ast_play_and_wait(chan, "digits/1");
09261 }
09262 if (!res)
09263 res = ast_play_and_wait(chan, "vm-opts");
09264 if (!res) {
09265 vms->starting = 0;
09266 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09267 }
09268 }
09269 return res;
09270 }
09271
09272 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09273 {
09274 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09275 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09276 } else {
09277 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09278 }
09279 }
09280
09281
09282 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09283 {
09284 int cmd = 0;
09285 int duration = 0;
09286 int tries = 0;
09287 char newpassword[80] = "";
09288 char newpassword2[80] = "";
09289 char prefile[PATH_MAX] = "";
09290 unsigned char buf[256];
09291 int bytes = 0;
09292
09293 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09294 if (ast_adsi_available(chan)) {
09295 bytes += adsi_logo(buf + bytes);
09296 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09297 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09298 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09299 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09300 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09301 }
09302
09303
09304 if (ast_test_flag(vmu, VM_FORCENAME)) {
09305 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09306 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09307 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09308 if (cmd < 0 || cmd == 't' || cmd == '#')
09309 return cmd;
09310 }
09311 }
09312
09313
09314 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09315 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09316 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09317 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09318 if (cmd < 0 || cmd == 't' || cmd == '#')
09319 return cmd;
09320 }
09321
09322 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09323 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09324 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09325 if (cmd < 0 || cmd == 't' || cmd == '#')
09326 return cmd;
09327 }
09328 }
09329
09330
09331
09332
09333
09334 for (;;) {
09335 newpassword[1] = '\0';
09336 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09337 if (cmd == '#')
09338 newpassword[0] = '\0';
09339 if (cmd < 0 || cmd == 't' || cmd == '#')
09340 return cmd;
09341 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09342 if (cmd < 0 || cmd == 't' || cmd == '#')
09343 return cmd;
09344 cmd = check_password(vmu, newpassword);
09345 if (cmd != 0) {
09346 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09347 cmd = ast_play_and_wait(chan, vm_invalid_password);
09348 } else {
09349 newpassword2[1] = '\0';
09350 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09351 if (cmd == '#')
09352 newpassword2[0] = '\0';
09353 if (cmd < 0 || cmd == 't' || cmd == '#')
09354 return cmd;
09355 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09356 if (cmd < 0 || cmd == 't' || cmd == '#')
09357 return cmd;
09358 if (!strcmp(newpassword, newpassword2))
09359 break;
09360 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09361 cmd = ast_play_and_wait(chan, vm_mismatch);
09362 }
09363 if (++tries == 3)
09364 return -1;
09365 if (cmd != 0) {
09366 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09367 }
09368 }
09369 if (pwdchange & PWDCHANGE_INTERNAL)
09370 vm_change_password(vmu, newpassword);
09371 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09372 vm_change_password_shell(vmu, newpassword);
09373
09374 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09375 cmd = ast_play_and_wait(chan, vm_passchanged);
09376
09377 return cmd;
09378 }
09379
09380 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09381 {
09382 int cmd = 0;
09383 int retries = 0;
09384 int duration = 0;
09385 char newpassword[80] = "";
09386 char newpassword2[80] = "";
09387 char prefile[PATH_MAX] = "";
09388 unsigned char buf[256];
09389 int bytes = 0;
09390
09391 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09392 if (ast_adsi_available(chan)) {
09393 bytes += adsi_logo(buf + bytes);
09394 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09395 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09396 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09397 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09398 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09399 }
09400 while ((cmd >= 0) && (cmd != 't')) {
09401 if (cmd)
09402 retries = 0;
09403 switch (cmd) {
09404 case '1':
09405 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09406 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09407 break;
09408 case '2':
09409 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09410 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09411 break;
09412 case '3':
09413 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09414 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09415 break;
09416 case '4':
09417 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09418 break;
09419 case '5':
09420 if (vmu->password[0] == '-') {
09421 cmd = ast_play_and_wait(chan, "vm-no");
09422 break;
09423 }
09424 newpassword[1] = '\0';
09425 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09426 if (cmd == '#')
09427 newpassword[0] = '\0';
09428 else {
09429 if (cmd < 0)
09430 break;
09431 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09432 break;
09433 }
09434 }
09435 cmd = check_password(vmu, newpassword);
09436 if (cmd != 0) {
09437 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09438 cmd = ast_play_and_wait(chan, vm_invalid_password);
09439 if (!cmd) {
09440 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09441 }
09442 break;
09443 }
09444 newpassword2[1] = '\0';
09445 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09446 if (cmd == '#')
09447 newpassword2[0] = '\0';
09448 else {
09449 if (cmd < 0)
09450 break;
09451
09452 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09453 break;
09454 }
09455 }
09456 if (strcmp(newpassword, newpassword2)) {
09457 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09458 cmd = ast_play_and_wait(chan, vm_mismatch);
09459 if (!cmd) {
09460 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09461 }
09462 break;
09463 }
09464
09465 if (pwdchange & PWDCHANGE_INTERNAL) {
09466 vm_change_password(vmu, newpassword);
09467 }
09468 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09469 vm_change_password_shell(vmu, newpassword);
09470 }
09471
09472 ast_debug(1, "User %s set password to %s of length %d\n",
09473 vms->username, newpassword, (int) strlen(newpassword));
09474 cmd = ast_play_and_wait(chan, vm_passchanged);
09475 break;
09476 case '*':
09477 cmd = 't';
09478 break;
09479 default:
09480 cmd = 0;
09481 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09482 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09483 if (ast_fileexists(prefile, NULL, NULL)) {
09484 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09485 }
09486 DISPOSE(prefile, -1);
09487 if (!cmd) {
09488 cmd = ast_play_and_wait(chan, "vm-options");
09489 }
09490 if (!cmd) {
09491 cmd = ast_waitfordigit(chan, 6000);
09492 }
09493 if (!cmd) {
09494 retries++;
09495 }
09496 if (retries > 3) {
09497 cmd = 't';
09498 }
09499 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09500 }
09501 }
09502 if (cmd == 't')
09503 cmd = 0;
09504 return cmd;
09505 }
09506
09507
09508
09509
09510
09511
09512
09513
09514
09515
09516
09517
09518
09519
09520
09521
09522
09523 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09524 {
09525 int cmd = 0;
09526 int retries = 0;
09527 int duration = 0;
09528 char prefile[PATH_MAX] = "";
09529 unsigned char buf[256];
09530 int bytes = 0;
09531
09532 if (ast_adsi_available(chan)) {
09533 bytes += adsi_logo(buf + bytes);
09534 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09535 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09536 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09537 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09538 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09539 }
09540
09541 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09542 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09543 while ((cmd >= 0) && (cmd != 't')) {
09544 if (cmd)
09545 retries = 0;
09546 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09547 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09548 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09549 if (cmd == -1) {
09550 break;
09551 }
09552 cmd = 't';
09553 } else {
09554 switch (cmd) {
09555 case '1':
09556 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09557 break;
09558 case '2':
09559 DELETE(prefile, -1, prefile, vmu);
09560 ast_play_and_wait(chan, "vm-tempremoved");
09561 cmd = 't';
09562 break;
09563 case '*':
09564 cmd = 't';
09565 break;
09566 default:
09567 cmd = ast_play_and_wait(chan,
09568 ast_fileexists(prefile, NULL, NULL) > 0 ?
09569 "vm-tempgreeting2" : "vm-tempgreeting");
09570 if (!cmd) {
09571 cmd = ast_waitfordigit(chan, 6000);
09572 }
09573 if (!cmd) {
09574 retries++;
09575 }
09576 if (retries > 3) {
09577 cmd = 't';
09578 }
09579 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09580 }
09581 }
09582 DISPOSE(prefile, -1);
09583 }
09584 if (cmd == 't')
09585 cmd = 0;
09586 return cmd;
09587 }
09588
09589
09590
09591 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09592 {
09593 int cmd = 0;
09594
09595 if (vms->lastmsg > -1) {
09596 cmd = play_message(chan, vmu, vms);
09597 } else {
09598 if (!strcasecmp(vms->fn, "INBOX")) {
09599 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09600 } else {
09601 cmd = ast_play_and_wait(chan, "vm-nomessages");
09602 }
09603 }
09604 return cmd;
09605 }
09606
09607
09608
09609
09610
09611
09612
09613
09614
09615 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09616 {
09617 int cmd = 0;
09618
09619 if (vms->lastmsg > -1) {
09620 cmd = play_message(chan, vmu, vms);
09621 } else {
09622 cmd = ast_play_and_wait(chan, "vm-youhave");
09623 if (!cmd)
09624 cmd = ast_play_and_wait(chan, "vm-no");
09625 if (!cmd) {
09626 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09627 cmd = ast_play_and_wait(chan, vms->fn);
09628 }
09629 if (!cmd)
09630 cmd = ast_play_and_wait(chan, "vm-messages");
09631 }
09632 return cmd;
09633 }
09634
09635
09636
09637
09638
09639
09640
09641
09642
09643
09644 static int vm_browse_messages_latin(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09645 {
09646 int cmd;
09647
09648 if (vms->lastmsg > -1) {
09649 cmd = play_message(chan, vmu, vms);
09650 } else {
09651 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09652 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09653 if (!cmd) {
09654 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09655 cmd = ast_play_and_wait(chan, vms->fn);
09656 }
09657 if (!cmd)
09658 cmd = ast_play_and_wait(chan, "vm-messages");
09659 } else {
09660 if (!cmd)
09661 cmd = ast_play_and_wait(chan, "vm-messages");
09662 if (!cmd) {
09663 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09664 cmd = ast_play_and_wait(chan, vms->fn);
09665 }
09666 }
09667 }
09668 return cmd;
09669 }
09670
09671
09672
09673
09674
09675
09676
09677
09678
09679 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09680 {
09681 int cmd;
09682
09683 if (vms->lastmsg > -1) {
09684 cmd = play_message(chan, vmu, vms);
09685 } else {
09686 cmd = ast_play_and_wait(chan, "vm-you");
09687 if (!cmd)
09688 cmd = ast_play_and_wait(chan, "vm-haveno");
09689 if (!cmd)
09690 cmd = ast_play_and_wait(chan, "vm-messages");
09691 if (!cmd) {
09692 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09693 cmd = ast_play_and_wait(chan, vms->fn);
09694 }
09695 }
09696 return cmd;
09697 }
09698
09699
09700
09701
09702
09703
09704
09705
09706
09707 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09708 {
09709 int cmd = 0;
09710
09711 if (vms->lastmsg > -1) {
09712 cmd = play_message(chan, vmu, vms);
09713 } else {
09714 cmd = ast_play_and_wait(chan, "vm-no");
09715 if (!cmd) {
09716 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09717 cmd = ast_play_and_wait(chan, vms->fn);
09718 }
09719 }
09720 return cmd;
09721 }
09722
09723
09724
09725
09726
09727
09728
09729
09730
09731
09732
09733
09734 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09735 {
09736 if (!strncasecmp(chan->language, "es", 2) ||
09737 !strncasecmp(chan->language, "it", 2) ||
09738 !strncasecmp(chan->language, "pt", 2) ||
09739 !strncasecmp(chan->language, "gr", 2)) {
09740 return vm_browse_messages_latin(chan, vms, vmu);
09741 } else if (!strncasecmp(chan->language, "he", 2)) {
09742 return vm_browse_messages_he(chan, vms, vmu);
09743 } else if (!strncasecmp(chan->language, "vi", 2)) {
09744 return vm_browse_messages_vi(chan, vms, vmu);
09745 } else if (!strncasecmp(chan->language, "zh", 2)) {
09746 return vm_browse_messages_zh(chan, vms, vmu);
09747 } else {
09748 return vm_browse_messages_en(chan, vms, vmu);
09749 }
09750 }
09751
09752 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09753 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09754 int skipuser, int max_logins, int silent)
09755 {
09756 int useadsi = 0, valid = 0, logretries = 0;
09757 char password[AST_MAX_EXTENSION]="", *passptr;
09758 struct ast_vm_user vmus, *vmu = NULL;
09759
09760
09761 adsi_begin(chan, &useadsi);
09762 if (!skipuser && useadsi)
09763 adsi_login(chan);
09764 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09765 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09766 return -1;
09767 }
09768
09769
09770
09771 while (!valid && (logretries < max_logins)) {
09772
09773 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09774 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09775 return -1;
09776 }
09777 if (ast_strlen_zero(mailbox)) {
09778 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09779 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09780 } else {
09781 ast_verb(3, "Username not entered\n");
09782 return -1;
09783 }
09784 } else if (mailbox[0] == '*') {
09785
09786 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09787 if (ast_exists_extension(chan, chan->context, "a", 1,
09788 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09789 return -1;
09790 }
09791 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09792 mailbox[0] = '\0';
09793 }
09794
09795 if (useadsi)
09796 adsi_password(chan);
09797
09798 if (!ast_strlen_zero(prefix)) {
09799 char fullusername[80] = "";
09800 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09801 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09802 ast_copy_string(mailbox, fullusername, mailbox_size);
09803 }
09804
09805 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09806 vmu = find_user(&vmus, context, mailbox);
09807 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09808
09809 password[0] = '\0';
09810 } else {
09811 if (ast_streamfile(chan, vm_password, chan->language)) {
09812 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09813 return -1;
09814 }
09815 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09816 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09817 return -1;
09818 } else if (password[0] == '*') {
09819
09820 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09821 if (ast_exists_extension(chan, chan->context, "a", 1,
09822 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09823 mailbox[0] = '*';
09824 return -1;
09825 }
09826 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09827 mailbox[0] = '\0';
09828
09829 vmu = NULL;
09830 }
09831 }
09832
09833 if (vmu) {
09834 passptr = vmu->password;
09835 if (passptr[0] == '-') passptr++;
09836 }
09837 if (vmu && !strcmp(passptr, password))
09838 valid++;
09839 else {
09840 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09841 if (!ast_strlen_zero(prefix))
09842 mailbox[0] = '\0';
09843 }
09844 logretries++;
09845 if (!valid) {
09846 if (skipuser || logretries >= max_logins) {
09847 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09848 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09849 return -1;
09850 }
09851 } else {
09852 if (useadsi)
09853 adsi_login(chan);
09854 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09855 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09856 return -1;
09857 }
09858 }
09859 if (ast_waitstream(chan, ""))
09860 return -1;
09861 }
09862 }
09863 if (!valid && (logretries >= max_logins)) {
09864 ast_stopstream(chan);
09865 ast_play_and_wait(chan, "vm-goodbye");
09866 return -1;
09867 }
09868 if (vmu && !skipuser) {
09869 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09870 }
09871 return 0;
09872 }
09873
09874 static int vm_execmain(struct ast_channel *chan, const char *data)
09875 {
09876
09877
09878
09879 int res = -1;
09880 int cmd = 0;
09881 int valid = 0;
09882 char prefixstr[80] ="";
09883 char ext_context[256]="";
09884 int box;
09885 int useadsi = 0;
09886 int skipuser = 0;
09887 struct vm_state vms;
09888 struct ast_vm_user *vmu = NULL, vmus;
09889 char *context = NULL;
09890 int silentexit = 0;
09891 struct ast_flags flags = { 0 };
09892 signed char record_gain = 0;
09893 int play_auto = 0;
09894 int play_folder = 0;
09895 int in_urgent = 0;
09896 #ifdef IMAP_STORAGE
09897 int deleted = 0;
09898 #endif
09899
09900
09901 memset(&vms, 0, sizeof(vms));
09902
09903 vms.lastmsg = -1;
09904
09905 memset(&vmus, 0, sizeof(vmus));
09906
09907 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09908 if (chan->_state != AST_STATE_UP) {
09909 ast_debug(1, "Before ast_answer\n");
09910 ast_answer(chan);
09911 }
09912
09913 if (!ast_strlen_zero(data)) {
09914 char *opts[OPT_ARG_ARRAY_SIZE];
09915 char *parse;
09916 AST_DECLARE_APP_ARGS(args,
09917 AST_APP_ARG(argv0);
09918 AST_APP_ARG(argv1);
09919 );
09920
09921 parse = ast_strdupa(data);
09922
09923 AST_STANDARD_APP_ARGS(args, parse);
09924
09925 if (args.argc == 2) {
09926 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09927 return -1;
09928 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09929 int gain;
09930 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09931 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09932 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09933 return -1;
09934 } else {
09935 record_gain = (signed char) gain;
09936 }
09937 } else {
09938 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09939 }
09940 }
09941 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09942 play_auto = 1;
09943 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09944
09945 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09946 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09947 play_folder = -1;
09948 }
09949 } else {
09950 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09951 }
09952 } else {
09953 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09954 }
09955 if (play_folder > 9 || play_folder < 0) {
09956 ast_log(AST_LOG_WARNING,
09957 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09958 opts[OPT_ARG_PLAYFOLDER]);
09959 play_folder = 0;
09960 }
09961 }
09962 } else {
09963
09964 while (*(args.argv0)) {
09965 if (*(args.argv0) == 's')
09966 ast_set_flag(&flags, OPT_SILENT);
09967 else if (*(args.argv0) == 'p')
09968 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09969 else
09970 break;
09971 (args.argv0)++;
09972 }
09973
09974 }
09975
09976 valid = ast_test_flag(&flags, OPT_SILENT);
09977
09978 if ((context = strchr(args.argv0, '@')))
09979 *context++ = '\0';
09980
09981 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09982 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09983 else
09984 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09985
09986 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09987 skipuser++;
09988 else
09989 valid = 0;
09990 }
09991
09992 if (!valid)
09993 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09994
09995 ast_debug(1, "After vm_authenticate\n");
09996
09997 if (vms.username[0] == '*') {
09998 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09999
10000
10001 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10002 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10003 res = 0;
10004 goto out;
10005 }
10006 }
10007
10008 if (!res) {
10009 valid = 1;
10010 if (!skipuser)
10011 vmu = &vmus;
10012 } else {
10013 res = 0;
10014 }
10015
10016
10017 adsi_begin(chan, &useadsi);
10018
10019 ast_test_suite_assert(valid);
10020 if (!valid) {
10021 goto out;
10022 }
10023 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10024
10025 #ifdef IMAP_STORAGE
10026 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10027 pthread_setspecific(ts_vmstate.key, &vms);
10028
10029 vms.interactive = 1;
10030 vms.updated = 1;
10031 if (vmu)
10032 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10033 vmstate_insert(&vms);
10034 init_vm_state(&vms);
10035 #endif
10036
10037
10038 if (!ast_strlen_zero(vmu->language))
10039 ast_string_field_set(chan, language, vmu->language);
10040
10041
10042 ast_debug(1, "Before open_mailbox\n");
10043 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10044 if (res < 0)
10045 goto out;
10046 vms.oldmessages = vms.lastmsg + 1;
10047 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10048
10049 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10050 if (res < 0)
10051 goto out;
10052 vms.newmessages = vms.lastmsg + 1;
10053 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10054
10055 in_urgent = 1;
10056 res = open_mailbox(&vms, vmu, 11);
10057 if (res < 0)
10058 goto out;
10059 vms.urgentmessages = vms.lastmsg + 1;
10060 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10061
10062
10063 if (play_auto) {
10064 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10065 if (vms.urgentmessages) {
10066 in_urgent = 1;
10067 res = open_mailbox(&vms, vmu, 11);
10068 } else {
10069 in_urgent = 0;
10070 res = open_mailbox(&vms, vmu, play_folder);
10071 }
10072 if (res < 0)
10073 goto out;
10074
10075
10076 if (vms.lastmsg == -1) {
10077 in_urgent = 0;
10078 cmd = vm_browse_messages(chan, &vms, vmu);
10079 res = 0;
10080 goto out;
10081 }
10082 } else {
10083 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10084
10085 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10086 in_urgent = 0;
10087 play_folder = 1;
10088 if (res < 0)
10089 goto out;
10090 } else if (!vms.urgentmessages && vms.newmessages) {
10091
10092 in_urgent = 0;
10093 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10094 if (res < 0)
10095 goto out;
10096 }
10097 }
10098
10099 if (useadsi)
10100 adsi_status(chan, &vms);
10101 res = 0;
10102
10103
10104 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10105 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10106 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10107 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10108 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10109 if ((cmd == 't') || (cmd == '#')) {
10110
10111 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10112 res = 0;
10113 goto out;
10114 } else if (cmd < 0) {
10115
10116 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10117 res = -1;
10118 goto out;
10119 }
10120 }
10121 #ifdef IMAP_STORAGE
10122 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10123 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10124 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10125 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10126 }
10127 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10128 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10129 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10130 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10131 }
10132 #endif
10133
10134 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10135 if (play_auto) {
10136 cmd = '1';
10137 } else {
10138 cmd = vm_intro(chan, vmu, &vms);
10139 }
10140 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10141
10142 vms.repeats = 0;
10143 vms.starting = 1;
10144 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10145
10146 switch (cmd) {
10147 case '1':
10148 vms.curmsg = 0;
10149
10150 case '5':
10151 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10152 cmd = vm_browse_messages(chan, &vms, vmu);
10153 break;
10154 case '2':
10155 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10156 if (useadsi)
10157 adsi_folders(chan, 0, "Change to folder...");
10158
10159 cmd = get_folder2(chan, "vm-changeto", 0);
10160 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10161 if (cmd == '#') {
10162 cmd = 0;
10163 } else if (cmd > 0) {
10164 cmd = cmd - '0';
10165 res = close_mailbox(&vms, vmu);
10166 if (res == ERROR_LOCK_PATH)
10167 goto out;
10168
10169 if (cmd != 11) in_urgent = 0;
10170 res = open_mailbox(&vms, vmu, cmd);
10171 if (res < 0)
10172 goto out;
10173 play_folder = cmd;
10174 cmd = 0;
10175 }
10176 if (useadsi)
10177 adsi_status2(chan, &vms);
10178
10179 if (!cmd) {
10180 cmd = vm_play_folder_name(chan, vms.vmbox);
10181 }
10182
10183 vms.starting = 1;
10184 vms.curmsg = 0;
10185 break;
10186 case '3':
10187 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10188 cmd = 0;
10189 vms.repeats = 0;
10190 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10191 switch (cmd) {
10192 case '1':
10193 if (vms.lastmsg > -1 && !vms.starting) {
10194 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10195 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10196 res = cmd;
10197 goto out;
10198 }
10199 } else {
10200 cmd = ast_play_and_wait(chan, "vm-sorry");
10201 }
10202 cmd = 't';
10203 break;
10204 case '2':
10205 if (!vms.starting)
10206 ast_verb(3, "Callback Requested\n");
10207 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10208 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10209 if (cmd == 9) {
10210 silentexit = 1;
10211 goto out;
10212 } else if (cmd == ERROR_LOCK_PATH) {
10213 res = cmd;
10214 goto out;
10215 }
10216 } else {
10217 cmd = ast_play_and_wait(chan, "vm-sorry");
10218 }
10219 cmd = 't';
10220 break;
10221 case '3':
10222 if (vms.lastmsg > -1 && !vms.starting) {
10223 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10224 if (cmd == ERROR_LOCK_PATH) {
10225 res = cmd;
10226 goto out;
10227 }
10228 } else {
10229 cmd = ast_play_and_wait(chan, "vm-sorry");
10230 }
10231 cmd = 't';
10232 break;
10233 case '4':
10234 if (!ast_strlen_zero(vmu->dialout)) {
10235 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10236 if (cmd == 9) {
10237 silentexit = 1;
10238 goto out;
10239 }
10240 } else {
10241 cmd = ast_play_and_wait(chan, "vm-sorry");
10242 }
10243 cmd = 't';
10244 break;
10245
10246 case '5':
10247 if (ast_test_flag(vmu, VM_SVMAIL)) {
10248 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10249 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10250 res = cmd;
10251 goto out;
10252 }
10253 } else {
10254 cmd = ast_play_and_wait(chan, "vm-sorry");
10255 }
10256 cmd = 't';
10257 break;
10258
10259 case '*':
10260 cmd = 't';
10261 break;
10262
10263 default:
10264 cmd = 0;
10265 if (!vms.starting) {
10266 cmd = ast_play_and_wait(chan, "vm-toreply");
10267 }
10268 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10269 cmd = ast_play_and_wait(chan, "vm-tocallback");
10270 }
10271 if (!cmd && !vms.starting) {
10272 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10273 }
10274 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10275 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10276 }
10277 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10278 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10279 }
10280 if (!cmd) {
10281 cmd = ast_play_and_wait(chan, "vm-starmain");
10282 }
10283 if (!cmd) {
10284 cmd = ast_waitfordigit(chan, 6000);
10285 }
10286 if (!cmd) {
10287 vms.repeats++;
10288 }
10289 if (vms.repeats > 3) {
10290 cmd = 't';
10291 }
10292 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10293 }
10294 }
10295 if (cmd == 't') {
10296 cmd = 0;
10297 vms.repeats = 0;
10298 }
10299 break;
10300 case '4':
10301 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10302 if (vms.curmsg > 0) {
10303 vms.curmsg--;
10304 cmd = play_message(chan, vmu, &vms);
10305 } else {
10306
10307
10308
10309
10310 if (in_urgent == 0 && vms.urgentmessages > 0) {
10311
10312 in_urgent = 1;
10313 res = close_mailbox(&vms, vmu);
10314 if (res == ERROR_LOCK_PATH)
10315 goto out;
10316 res = open_mailbox(&vms, vmu, 11);
10317 if (res < 0)
10318 goto out;
10319 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10320 vms.curmsg = vms.lastmsg;
10321 if (vms.lastmsg < 0) {
10322 cmd = ast_play_and_wait(chan, "vm-nomore");
10323 }
10324 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10325 vms.curmsg = vms.lastmsg;
10326 cmd = play_message(chan, vmu, &vms);
10327 } else {
10328 cmd = ast_play_and_wait(chan, "vm-nomore");
10329 }
10330 }
10331 break;
10332 case '6':
10333 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10334 if (vms.curmsg < vms.lastmsg) {
10335 vms.curmsg++;
10336 cmd = play_message(chan, vmu, &vms);
10337 } else {
10338 if (in_urgent && vms.newmessages > 0) {
10339
10340
10341
10342
10343 in_urgent = 0;
10344 res = close_mailbox(&vms, vmu);
10345 if (res == ERROR_LOCK_PATH)
10346 goto out;
10347 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10348 if (res < 0)
10349 goto out;
10350 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10351 vms.curmsg = -1;
10352 if (vms.lastmsg < 0) {
10353 cmd = ast_play_and_wait(chan, "vm-nomore");
10354 }
10355 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10356 vms.curmsg = 0;
10357 cmd = play_message(chan, vmu, &vms);
10358 } else {
10359 cmd = ast_play_and_wait(chan, "vm-nomore");
10360 }
10361 }
10362 break;
10363 case '7':
10364 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10365 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10366 if (useadsi)
10367 adsi_delete(chan, &vms);
10368 if (vms.deleted[vms.curmsg]) {
10369 if (play_folder == 0) {
10370 if (in_urgent) {
10371 vms.urgentmessages--;
10372 } else {
10373 vms.newmessages--;
10374 }
10375 }
10376 else if (play_folder == 1)
10377 vms.oldmessages--;
10378 cmd = ast_play_and_wait(chan, "vm-deleted");
10379 } else {
10380 if (play_folder == 0) {
10381 if (in_urgent) {
10382 vms.urgentmessages++;
10383 } else {
10384 vms.newmessages++;
10385 }
10386 }
10387 else if (play_folder == 1)
10388 vms.oldmessages++;
10389 cmd = ast_play_and_wait(chan, "vm-undeleted");
10390 }
10391 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10392 if (vms.curmsg < vms.lastmsg) {
10393 vms.curmsg++;
10394 cmd = play_message(chan, vmu, &vms);
10395 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10396 vms.curmsg = 0;
10397 cmd = play_message(chan, vmu, &vms);
10398 } else {
10399
10400
10401
10402
10403 if (in_urgent == 1) {
10404
10405 in_urgent = 0;
10406 res = close_mailbox(&vms, vmu);
10407 if (res == ERROR_LOCK_PATH)
10408 goto out;
10409 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10410 if (res < 0)
10411 goto out;
10412 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10413 vms.curmsg = -1;
10414 if (vms.lastmsg < 0) {
10415 cmd = ast_play_and_wait(chan, "vm-nomore");
10416 }
10417 } else {
10418 cmd = ast_play_and_wait(chan, "vm-nomore");
10419 }
10420 }
10421 }
10422 } else
10423 cmd = 0;
10424 #ifdef IMAP_STORAGE
10425 deleted = 1;
10426 #endif
10427 break;
10428
10429 case '8':
10430 if (vms.lastmsg > -1) {
10431 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10432 if (cmd == ERROR_LOCK_PATH) {
10433 res = cmd;
10434 goto out;
10435 }
10436 } else {
10437
10438
10439
10440
10441 if (in_urgent == 1 && vms.newmessages > 0) {
10442
10443 in_urgent = 0;
10444 res = close_mailbox(&vms, vmu);
10445 if (res == ERROR_LOCK_PATH)
10446 goto out;
10447 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10448 if (res < 0)
10449 goto out;
10450 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10451 vms.curmsg = -1;
10452 if (vms.lastmsg < 0) {
10453 cmd = ast_play_and_wait(chan, "vm-nomore");
10454 }
10455 } else {
10456 cmd = ast_play_and_wait(chan, "vm-nomore");
10457 }
10458 }
10459 break;
10460 case '9':
10461 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10462 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10463
10464 cmd = 0;
10465 break;
10466 }
10467 if (useadsi)
10468 adsi_folders(chan, 1, "Save to folder...");
10469 cmd = get_folder2(chan, "vm-savefolder", 1);
10470 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10471 box = 0;
10472 if (cmd == '#') {
10473 cmd = 0;
10474 break;
10475 } else if (cmd > 0) {
10476 box = cmd = cmd - '0';
10477 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10478 if (cmd == ERROR_LOCK_PATH) {
10479 res = cmd;
10480 goto out;
10481 #ifndef IMAP_STORAGE
10482 } else if (!cmd) {
10483 vms.deleted[vms.curmsg] = 1;
10484 #endif
10485 } else {
10486 vms.deleted[vms.curmsg] = 0;
10487 vms.heard[vms.curmsg] = 0;
10488 }
10489 }
10490 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10491 if (useadsi)
10492 adsi_message(chan, &vms);
10493 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10494 if (!cmd) {
10495 cmd = ast_play_and_wait(chan, "vm-message");
10496 if (!cmd)
10497 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10498 if (!cmd)
10499 cmd = ast_play_and_wait(chan, "vm-savedto");
10500 if (!cmd)
10501 cmd = vm_play_folder_name(chan, vms.fn);
10502 } else {
10503 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10504 }
10505 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10506 if (vms.curmsg < vms.lastmsg) {
10507 vms.curmsg++;
10508 cmd = play_message(chan, vmu, &vms);
10509 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10510 vms.curmsg = 0;
10511 cmd = play_message(chan, vmu, &vms);
10512 } else {
10513
10514
10515
10516
10517 if (in_urgent == 1 && vms.newmessages > 0) {
10518
10519 in_urgent = 0;
10520 res = close_mailbox(&vms, vmu);
10521 if (res == ERROR_LOCK_PATH)
10522 goto out;
10523 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10524 if (res < 0)
10525 goto out;
10526 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10527 vms.curmsg = -1;
10528 if (vms.lastmsg < 0) {
10529 cmd = ast_play_and_wait(chan, "vm-nomore");
10530 }
10531 } else {
10532 cmd = ast_play_and_wait(chan, "vm-nomore");
10533 }
10534 }
10535 }
10536 break;
10537 case '*':
10538 if (!vms.starting) {
10539 cmd = ast_play_and_wait(chan, "vm-onefor");
10540 if (!strncasecmp(chan->language, "he", 2)) {
10541 cmd = ast_play_and_wait(chan, "vm-for");
10542 }
10543 if (!cmd)
10544 cmd = vm_play_folder_name(chan, vms.vmbox);
10545 if (!cmd)
10546 cmd = ast_play_and_wait(chan, "vm-opts");
10547 if (!cmd)
10548 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10549 } else
10550 cmd = 0;
10551 break;
10552 case '0':
10553 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10554 if (useadsi)
10555 adsi_status(chan, &vms);
10556 break;
10557 default:
10558 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10559 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10560 break;
10561 }
10562 }
10563 if ((cmd == 't') || (cmd == '#')) {
10564
10565 res = 0;
10566 } else {
10567
10568 res = -1;
10569 }
10570
10571 out:
10572 if (res > -1) {
10573 ast_stopstream(chan);
10574 adsi_goodbye(chan);
10575 if (valid && res != OPERATOR_EXIT) {
10576 if (silentexit)
10577 res = ast_play_and_wait(chan, "vm-dialout");
10578 else
10579 res = ast_play_and_wait(chan, "vm-goodbye");
10580 }
10581 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10582 res = 0;
10583 }
10584 if (useadsi)
10585 ast_adsi_unload_session(chan);
10586 }
10587 if (vmu)
10588 close_mailbox(&vms, vmu);
10589 if (valid) {
10590 int new = 0, old = 0, urgent = 0;
10591 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10592 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10593
10594 run_externnotify(vmu->context, vmu->mailbox, NULL);
10595 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10596 queue_mwi_event(ext_context, urgent, new, old);
10597 }
10598 #ifdef IMAP_STORAGE
10599
10600 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10601 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10602 ast_mutex_lock(&vms.lock);
10603 #ifdef HAVE_IMAP_TK2006
10604 if (LEVELUIDPLUS (vms.mailstream)) {
10605 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10606 } else
10607 #endif
10608 mail_expunge(vms.mailstream);
10609 ast_mutex_unlock(&vms.lock);
10610 }
10611
10612
10613 if (vmu) {
10614 vmstate_delete(&vms);
10615 }
10616 #endif
10617 if (vmu)
10618 free_user(vmu);
10619
10620 #ifdef IMAP_STORAGE
10621 pthread_setspecific(ts_vmstate.key, NULL);
10622 #endif
10623 return res;
10624 }
10625
10626 static int vm_exec(struct ast_channel *chan, const char *data)
10627 {
10628 int res = 0;
10629 char *tmp;
10630 struct leave_vm_options leave_options;
10631 struct ast_flags flags = { 0 };
10632 char *opts[OPT_ARG_ARRAY_SIZE];
10633 AST_DECLARE_APP_ARGS(args,
10634 AST_APP_ARG(argv0);
10635 AST_APP_ARG(argv1);
10636 );
10637
10638 memset(&leave_options, 0, sizeof(leave_options));
10639
10640 if (chan->_state != AST_STATE_UP)
10641 ast_answer(chan);
10642
10643 if (!ast_strlen_zero(data)) {
10644 tmp = ast_strdupa(data);
10645 AST_STANDARD_APP_ARGS(args, tmp);
10646 if (args.argc == 2) {
10647 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10648 return -1;
10649 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10650 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10651 int gain;
10652
10653 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10654 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10655 return -1;
10656 } else {
10657 leave_options.record_gain = (signed char) gain;
10658 }
10659 }
10660 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10661 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10662 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10663 }
10664 }
10665 } else {
10666 char temp[256];
10667 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10668 if (res < 0)
10669 return res;
10670 if (ast_strlen_zero(temp))
10671 return 0;
10672 args.argv0 = ast_strdupa(temp);
10673 }
10674
10675 res = leave_voicemail(chan, args.argv0, &leave_options);
10676 if (res == 't') {
10677 ast_play_and_wait(chan, "vm-goodbye");
10678 res = 0;
10679 }
10680
10681 if (res == OPERATOR_EXIT) {
10682 res = 0;
10683 }
10684
10685 if (res == ERROR_LOCK_PATH) {
10686 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10687 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10688 res = 0;
10689 }
10690
10691 return res;
10692 }
10693
10694 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10695 {
10696 struct ast_vm_user *vmu;
10697
10698 if (!ast_strlen_zero(box) && box[0] == '*') {
10699 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10700 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10701 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10702 "\n\tand will be ignored.\n", box, context);
10703 return NULL;
10704 }
10705
10706 AST_LIST_TRAVERSE(&users, vmu, list) {
10707 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10708 if (strcasecmp(vmu->context, context)) {
10709 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10710 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10711 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10712 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10713 }
10714 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10715 return NULL;
10716 }
10717 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10718 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10719 return NULL;
10720 }
10721 }
10722
10723 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10724 return NULL;
10725
10726 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10727 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10728
10729 AST_LIST_INSERT_TAIL(&users, vmu, list);
10730
10731 return vmu;
10732 }
10733
10734 static int append_mailbox(const char *context, const char *box, const char *data)
10735 {
10736
10737 char *tmp;
10738 char *stringp;
10739 char *s;
10740 struct ast_vm_user *vmu;
10741 char *mailbox_full;
10742 int new = 0, old = 0, urgent = 0;
10743 char secretfn[PATH_MAX] = "";
10744
10745 tmp = ast_strdupa(data);
10746
10747 if (!(vmu = find_or_create(context, box)))
10748 return -1;
10749
10750 populate_defaults(vmu);
10751
10752 stringp = tmp;
10753 if ((s = strsep(&stringp, ","))) {
10754 if (!ast_strlen_zero(s) && s[0] == '*') {
10755 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10756 "\n\tmust be reset in voicemail.conf.\n", box);
10757 }
10758
10759 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10760 }
10761 if (stringp && (s = strsep(&stringp, ","))) {
10762 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10763 }
10764 if (stringp && (s = strsep(&stringp, ","))) {
10765 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10766 }
10767 if (stringp && (s = strsep(&stringp, ","))) {
10768 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10769 }
10770 if (stringp && (s = strsep(&stringp, ","))) {
10771 apply_options(vmu, s);
10772 }
10773
10774 switch (vmu->passwordlocation) {
10775 case OPT_PWLOC_SPOOLDIR:
10776 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10777 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10778 }
10779
10780 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
10781 strcpy(mailbox_full, box);
10782 strcat(mailbox_full, "@");
10783 strcat(mailbox_full, context);
10784
10785 inboxcount2(mailbox_full, &urgent, &new, &old);
10786 queue_mwi_event(mailbox_full, urgent, new, old);
10787
10788 return 0;
10789 }
10790
10791 AST_TEST_DEFINE(test_voicemail_vmuser)
10792 {
10793 int res = 0;
10794 struct ast_vm_user *vmu;
10795
10796 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10797 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10798 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10799 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10800 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10801 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10802 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10803 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10804 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10805 #ifdef IMAP_STORAGE
10806 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10807 "imapfolder=INBOX|imapvmshareid=6000";
10808 #endif
10809
10810 switch (cmd) {
10811 case TEST_INIT:
10812 info->name = "vmuser";
10813 info->category = "/apps/app_voicemail/";
10814 info->summary = "Vmuser unit test";
10815 info->description =
10816 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10817 return AST_TEST_NOT_RUN;
10818 case TEST_EXECUTE:
10819 break;
10820 }
10821
10822 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10823 return AST_TEST_NOT_RUN;
10824 }
10825 populate_defaults(vmu);
10826 ast_set_flag(vmu, VM_ALLOCED);
10827
10828 apply_options(vmu, options_string);
10829
10830 if (!ast_test_flag(vmu, VM_ATTACH)) {
10831 ast_test_status_update(test, "Parse failure for attach option\n");
10832 res = 1;
10833 }
10834 if (strcasecmp(vmu->attachfmt, "wav49")) {
10835 ast_test_status_update(test, "Parse failure for attachftm option\n");
10836 res = 1;
10837 }
10838 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10839 ast_test_status_update(test, "Parse failure for serveremail option\n");
10840 res = 1;
10841 }
10842 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10843 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10844 res = 1;
10845 }
10846 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10847 ast_test_status_update(test, "Parse failure for emailbody option\n");
10848 res = 1;
10849 }
10850 if (strcasecmp(vmu->zonetag, "central")) {
10851 ast_test_status_update(test, "Parse failure for tz option\n");
10852 res = 1;
10853 }
10854 if (!ast_test_flag(vmu, VM_DELETE)) {
10855 ast_test_status_update(test, "Parse failure for delete option\n");
10856 res = 1;
10857 }
10858 if (!ast_test_flag(vmu, VM_SAYCID)) {
10859 ast_test_status_update(test, "Parse failure for saycid option\n");
10860 res = 1;
10861 }
10862 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10863 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10864 res = 1;
10865 }
10866 if (!ast_test_flag(vmu, VM_REVIEW)) {
10867 ast_test_status_update(test, "Parse failure for review option\n");
10868 res = 1;
10869 }
10870 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10871 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10872 res = 1;
10873 }
10874 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10875 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10876 res = 1;
10877 }
10878 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10879 ast_test_status_update(test, "Parse failure for operator option\n");
10880 res = 1;
10881 }
10882 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10883 ast_test_status_update(test, "Parse failure for envelope option\n");
10884 res = 1;
10885 }
10886 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10887 ast_test_status_update(test, "Parse failure for moveheard option\n");
10888 res = 1;
10889 }
10890 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10891 ast_test_status_update(test, "Parse failure for sayduration option\n");
10892 res = 1;
10893 }
10894 if (vmu->saydurationm != 5) {
10895 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10896 res = 1;
10897 }
10898 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10899 ast_test_status_update(test, "Parse failure for forcename option\n");
10900 res = 1;
10901 }
10902 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10903 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10904 res = 1;
10905 }
10906 if (strcasecmp(vmu->callback, "somecontext")) {
10907 ast_test_status_update(test, "Parse failure for callbacks option\n");
10908 res = 1;
10909 }
10910 if (strcasecmp(vmu->dialout, "somecontext2")) {
10911 ast_test_status_update(test, "Parse failure for dialout option\n");
10912 res = 1;
10913 }
10914 if (strcasecmp(vmu->exit, "somecontext3")) {
10915 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10916 res = 1;
10917 }
10918 if (vmu->minsecs != 10) {
10919 ast_test_status_update(test, "Parse failure for minsecs option\n");
10920 res = 1;
10921 }
10922 if (vmu->maxsecs != 100) {
10923 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10924 res = 1;
10925 }
10926 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10927 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10928 res = 1;
10929 }
10930 if (vmu->maxdeletedmsg != 50) {
10931 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10932 res = 1;
10933 }
10934 if (vmu->volgain != 1.3) {
10935 ast_test_status_update(test, "Parse failure for volgain option\n");
10936 res = 1;
10937 }
10938 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10939 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10940 res = 1;
10941 }
10942 #ifdef IMAP_STORAGE
10943 apply_options(vmu, option_string2);
10944
10945 if (strcasecmp(vmu->imapuser, "imapuser")) {
10946 ast_test_status_update(test, "Parse failure for imapuser option\n");
10947 res = 1;
10948 }
10949 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10950 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10951 res = 1;
10952 }
10953 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10954 ast_test_status_update(test, "Parse failure for imapfolder option\n");
10955 res = 1;
10956 }
10957 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10958 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10959 res = 1;
10960 }
10961 #endif
10962
10963 free_user(vmu);
10964 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10965 }
10966
10967 static int vm_box_exists(struct ast_channel *chan, const char *data)
10968 {
10969 struct ast_vm_user svm;
10970 char *context, *box;
10971 AST_DECLARE_APP_ARGS(args,
10972 AST_APP_ARG(mbox);
10973 AST_APP_ARG(options);
10974 );
10975 static int dep_warning = 0;
10976
10977 if (ast_strlen_zero(data)) {
10978 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10979 return -1;
10980 }
10981
10982 if (!dep_warning) {
10983 dep_warning = 1;
10984 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10985 }
10986
10987 box = ast_strdupa(data);
10988
10989 AST_STANDARD_APP_ARGS(args, box);
10990
10991 if (args.options) {
10992 }
10993
10994 if ((context = strchr(args.mbox, '@'))) {
10995 *context = '\0';
10996 context++;
10997 }
10998
10999 if (find_user(&svm, context, args.mbox)) {
11000 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11001 } else
11002 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11003
11004 return 0;
11005 }
11006
11007 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11008 {
11009 struct ast_vm_user svm;
11010 AST_DECLARE_APP_ARGS(arg,
11011 AST_APP_ARG(mbox);
11012 AST_APP_ARG(context);
11013 );
11014
11015 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11016
11017 if (ast_strlen_zero(arg.mbox)) {
11018 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11019 return -1;
11020 }
11021
11022 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11023 return 0;
11024 }
11025
11026 static struct ast_custom_function mailbox_exists_acf = {
11027 .name = "MAILBOX_EXISTS",
11028 .read = acf_mailbox_exists,
11029 };
11030
11031 static int vmauthenticate(struct ast_channel *chan, const char *data)
11032 {
11033 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11034 struct ast_vm_user vmus;
11035 char *options = NULL;
11036 int silent = 0, skipuser = 0;
11037 int res = -1;
11038
11039 if (data) {
11040 s = ast_strdupa(data);
11041 user = strsep(&s, ",");
11042 options = strsep(&s, ",");
11043 if (user) {
11044 s = user;
11045 user = strsep(&s, "@");
11046 context = strsep(&s, "");
11047 if (!ast_strlen_zero(user))
11048 skipuser++;
11049 ast_copy_string(mailbox, user, sizeof(mailbox));
11050 }
11051 }
11052
11053 if (options) {
11054 silent = (strchr(options, 's')) != NULL;
11055 }
11056
11057 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11058 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11059 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11060 ast_play_and_wait(chan, "auth-thankyou");
11061 res = 0;
11062 } else if (mailbox[0] == '*') {
11063
11064 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11065 res = 0;
11066 }
11067 }
11068
11069 return res;
11070 }
11071
11072 static char *show_users_realtime(int fd, const char *context)
11073 {
11074 struct ast_config *cfg;
11075 const char *cat = NULL;
11076
11077 if (!(cfg = ast_load_realtime_multientry("voicemail",
11078 "context", context, SENTINEL))) {
11079 return CLI_FAILURE;
11080 }
11081
11082 ast_cli(fd,
11083 "\n"
11084 "=============================================================\n"
11085 "=== Configured Voicemail Users ==============================\n"
11086 "=============================================================\n"
11087 "===\n");
11088
11089 while ((cat = ast_category_browse(cfg, cat))) {
11090 struct ast_variable *var = NULL;
11091 ast_cli(fd,
11092 "=== Mailbox ...\n"
11093 "===\n");
11094 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11095 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11096 ast_cli(fd,
11097 "===\n"
11098 "=== ---------------------------------------------------------\n"
11099 "===\n");
11100 }
11101
11102 ast_cli(fd,
11103 "=============================================================\n"
11104 "\n");
11105
11106 ast_config_destroy(cfg);
11107
11108 return CLI_SUCCESS;
11109 }
11110
11111 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11112 {
11113 int which = 0;
11114 int wordlen;
11115 struct ast_vm_user *vmu;
11116 const char *context = "";
11117
11118
11119 if (pos > 4)
11120 return NULL;
11121 if (pos == 3)
11122 return (state == 0) ? ast_strdup("for") : NULL;
11123 wordlen = strlen(word);
11124 AST_LIST_TRAVERSE(&users, vmu, list) {
11125 if (!strncasecmp(word, vmu->context, wordlen)) {
11126 if (context && strcmp(context, vmu->context) && ++which > state)
11127 return ast_strdup(vmu->context);
11128
11129 context = vmu->context;
11130 }
11131 }
11132 return NULL;
11133 }
11134
11135
11136 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11137 {
11138 struct ast_vm_user *vmu;
11139 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11140 const char *context = NULL;
11141 int users_counter = 0;
11142
11143 switch (cmd) {
11144 case CLI_INIT:
11145 e->command = "voicemail show users";
11146 e->usage =
11147 "Usage: voicemail show users [for <context>]\n"
11148 " Lists all mailboxes currently set up\n";
11149 return NULL;
11150 case CLI_GENERATE:
11151 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11152 }
11153
11154 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11155 return CLI_SHOWUSAGE;
11156 if (a->argc == 5) {
11157 if (strcmp(a->argv[3],"for"))
11158 return CLI_SHOWUSAGE;
11159 context = a->argv[4];
11160 }
11161
11162 if (ast_check_realtime("voicemail")) {
11163 if (!context) {
11164 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11165 return CLI_SHOWUSAGE;
11166 }
11167 return show_users_realtime(a->fd, context);
11168 }
11169
11170 AST_LIST_LOCK(&users);
11171 if (AST_LIST_EMPTY(&users)) {
11172 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11173 AST_LIST_UNLOCK(&users);
11174 return CLI_FAILURE;
11175 }
11176 if (!context) {
11177 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11178 } else {
11179 int count = 0;
11180 AST_LIST_TRAVERSE(&users, vmu, list) {
11181 if (!strcmp(context, vmu->context)) {
11182 count++;
11183 break;
11184 }
11185 }
11186 if (count) {
11187 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11188 } else {
11189 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11190 AST_LIST_UNLOCK(&users);
11191 return CLI_FAILURE;
11192 }
11193 }
11194 AST_LIST_TRAVERSE(&users, vmu, list) {
11195 int newmsgs = 0, oldmsgs = 0;
11196 char count[12], tmp[256] = "";
11197
11198 if (!context || !strcmp(context, vmu->context)) {
11199 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11200 inboxcount(tmp, &newmsgs, &oldmsgs);
11201 snprintf(count, sizeof(count), "%d", newmsgs);
11202 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11203 users_counter++;
11204 }
11205 }
11206 AST_LIST_UNLOCK(&users);
11207 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11208 return CLI_SUCCESS;
11209 }
11210
11211
11212 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11213 {
11214 struct vm_zone *zone;
11215 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11216 char *res = CLI_SUCCESS;
11217
11218 switch (cmd) {
11219 case CLI_INIT:
11220 e->command = "voicemail show zones";
11221 e->usage =
11222 "Usage: voicemail show zones\n"
11223 " Lists zone message formats\n";
11224 return NULL;
11225 case CLI_GENERATE:
11226 return NULL;
11227 }
11228
11229 if (a->argc != 3)
11230 return CLI_SHOWUSAGE;
11231
11232 AST_LIST_LOCK(&zones);
11233 if (!AST_LIST_EMPTY(&zones)) {
11234 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11235 AST_LIST_TRAVERSE(&zones, zone, list) {
11236 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11237 }
11238 } else {
11239 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11240 res = CLI_FAILURE;
11241 }
11242 AST_LIST_UNLOCK(&zones);
11243
11244 return res;
11245 }
11246
11247
11248 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11249 {
11250 switch (cmd) {
11251 case CLI_INIT:
11252 e->command = "voicemail reload";
11253 e->usage =
11254 "Usage: voicemail reload\n"
11255 " Reload voicemail configuration\n";
11256 return NULL;
11257 case CLI_GENERATE:
11258 return NULL;
11259 }
11260
11261 if (a->argc != 2)
11262 return CLI_SHOWUSAGE;
11263
11264 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11265 load_config(1);
11266
11267 return CLI_SUCCESS;
11268 }
11269
11270 static struct ast_cli_entry cli_voicemail[] = {
11271 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11272 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11273 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11274 };
11275
11276 #ifdef IMAP_STORAGE
11277 #define DATA_EXPORT_VM_USERS(USER) \
11278 USER(ast_vm_user, context, AST_DATA_STRING) \
11279 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11280 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11281 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11282 USER(ast_vm_user, email, AST_DATA_STRING) \
11283 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11284 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11285 USER(ast_vm_user, pager, AST_DATA_STRING) \
11286 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11287 USER(ast_vm_user, language, AST_DATA_STRING) \
11288 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11289 USER(ast_vm_user, callback, AST_DATA_STRING) \
11290 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11291 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11292 USER(ast_vm_user, exit, AST_DATA_STRING) \
11293 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11294 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11295 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11296 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11297 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11298 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11299 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11300 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11301 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11302 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11303 #else
11304 #define DATA_EXPORT_VM_USERS(USER) \
11305 USER(ast_vm_user, context, AST_DATA_STRING) \
11306 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11307 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11308 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11309 USER(ast_vm_user, email, AST_DATA_STRING) \
11310 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11311 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11312 USER(ast_vm_user, pager, AST_DATA_STRING) \
11313 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11314 USER(ast_vm_user, language, AST_DATA_STRING) \
11315 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11316 USER(ast_vm_user, callback, AST_DATA_STRING) \
11317 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11318 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11319 USER(ast_vm_user, exit, AST_DATA_STRING) \
11320 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11321 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11322 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11323 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11324 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11325 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11326 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11327 #endif
11328
11329 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11330
11331 #define DATA_EXPORT_VM_ZONES(ZONE) \
11332 ZONE(vm_zone, name, AST_DATA_STRING) \
11333 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11334 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11335
11336 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11337
11338
11339
11340
11341
11342
11343
11344
11345 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11346 struct ast_data *data_root, struct ast_vm_user *user)
11347 {
11348 struct ast_data *data_user, *data_zone;
11349 struct ast_data *data_state;
11350 struct vm_zone *zone = NULL;
11351 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11352 char ext_context[256] = "";
11353
11354 data_user = ast_data_add_node(data_root, "user");
11355 if (!data_user) {
11356 return -1;
11357 }
11358
11359 ast_data_add_structure(ast_vm_user, data_user, user);
11360
11361 AST_LIST_LOCK(&zones);
11362 AST_LIST_TRAVERSE(&zones, zone, list) {
11363 if (!strcmp(zone->name, user->zonetag)) {
11364 break;
11365 }
11366 }
11367 AST_LIST_UNLOCK(&zones);
11368
11369
11370 data_state = ast_data_add_node(data_user, "state");
11371 if (!data_state) {
11372 return -1;
11373 }
11374 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11375 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11376 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11377 ast_data_add_int(data_state, "newmsg", newmsg);
11378 ast_data_add_int(data_state, "oldmsg", oldmsg);
11379
11380 if (zone) {
11381 data_zone = ast_data_add_node(data_user, "zone");
11382 ast_data_add_structure(vm_zone, data_zone, zone);
11383 }
11384
11385 if (!ast_data_search_match(search, data_user)) {
11386 ast_data_remove_node(data_root, data_user);
11387 }
11388
11389 return 0;
11390 }
11391
11392 static int vm_users_data_provider_get(const struct ast_data_search *search,
11393 struct ast_data *data_root)
11394 {
11395 struct ast_vm_user *user;
11396
11397 AST_LIST_LOCK(&users);
11398 AST_LIST_TRAVERSE(&users, user, list) {
11399 vm_users_data_provider_get_helper(search, data_root, user);
11400 }
11401 AST_LIST_UNLOCK(&users);
11402
11403 return 0;
11404 }
11405
11406 static const struct ast_data_handler vm_users_data_provider = {
11407 .version = AST_DATA_HANDLER_VERSION,
11408 .get = vm_users_data_provider_get
11409 };
11410
11411 static const struct ast_data_entry vm_data_providers[] = {
11412 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11413 };
11414
11415 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11416 {
11417 int new = 0, old = 0, urgent = 0;
11418
11419 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11420
11421 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11422 mwi_sub->old_urgent = urgent;
11423 mwi_sub->old_new = new;
11424 mwi_sub->old_old = old;
11425 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11426 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11427 }
11428 }
11429
11430 static void poll_subscribed_mailboxes(void)
11431 {
11432 struct mwi_sub *mwi_sub;
11433
11434 AST_RWLIST_RDLOCK(&mwi_subs);
11435 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11436 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11437 poll_subscribed_mailbox(mwi_sub);
11438 }
11439 }
11440 AST_RWLIST_UNLOCK(&mwi_subs);
11441 }
11442
11443 static void *mb_poll_thread(void *data)
11444 {
11445 while (poll_thread_run) {
11446 struct timespec ts = { 0, };
11447 struct timeval wait;
11448
11449 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11450 ts.tv_sec = wait.tv_sec;
11451 ts.tv_nsec = wait.tv_usec * 1000;
11452
11453 ast_mutex_lock(&poll_lock);
11454 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11455 ast_mutex_unlock(&poll_lock);
11456
11457 if (!poll_thread_run)
11458 break;
11459
11460 poll_subscribed_mailboxes();
11461 }
11462
11463 return NULL;
11464 }
11465
11466 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11467 {
11468 ast_free(mwi_sub);
11469 }
11470
11471 static int handle_unsubscribe(void *datap)
11472 {
11473 struct mwi_sub *mwi_sub;
11474 uint32_t *uniqueid = datap;
11475
11476 AST_RWLIST_WRLOCK(&mwi_subs);
11477 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11478 if (mwi_sub->uniqueid == *uniqueid) {
11479 AST_LIST_REMOVE_CURRENT(entry);
11480 break;
11481 }
11482 }
11483 AST_RWLIST_TRAVERSE_SAFE_END
11484 AST_RWLIST_UNLOCK(&mwi_subs);
11485
11486 if (mwi_sub)
11487 mwi_sub_destroy(mwi_sub);
11488
11489 ast_free(uniqueid);
11490 return 0;
11491 }
11492
11493 static int handle_subscribe(void *datap)
11494 {
11495 unsigned int len;
11496 struct mwi_sub *mwi_sub;
11497 struct mwi_sub_task *p = datap;
11498
11499 len = sizeof(*mwi_sub);
11500 if (!ast_strlen_zero(p->mailbox))
11501 len += strlen(p->mailbox);
11502
11503 if (!ast_strlen_zero(p->context))
11504 len += strlen(p->context) + 1;
11505
11506 if (!(mwi_sub = ast_calloc(1, len)))
11507 return -1;
11508
11509 mwi_sub->uniqueid = p->uniqueid;
11510 if (!ast_strlen_zero(p->mailbox))
11511 strcpy(mwi_sub->mailbox, p->mailbox);
11512
11513 if (!ast_strlen_zero(p->context)) {
11514 strcat(mwi_sub->mailbox, "@");
11515 strcat(mwi_sub->mailbox, p->context);
11516 }
11517
11518 AST_RWLIST_WRLOCK(&mwi_subs);
11519 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11520 AST_RWLIST_UNLOCK(&mwi_subs);
11521 ast_free((void *) p->mailbox);
11522 ast_free((void *) p->context);
11523 ast_free(p);
11524 poll_subscribed_mailbox(mwi_sub);
11525 return 0;
11526 }
11527
11528 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11529 {
11530 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11531
11532 if (!uniqueid) {
11533 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11534 return;
11535 }
11536
11537 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11538 ast_free(uniqueid);
11539 return;
11540 }
11541
11542 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11543 ast_free(uniqueid);
11544 return;
11545 }
11546
11547 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11548 *uniqueid = u;
11549 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11550 ast_free(uniqueid);
11551 }
11552 }
11553
11554 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11555 {
11556 struct mwi_sub_task *mwist;
11557
11558 if (ast_event_get_type(event) != AST_EVENT_SUB)
11559 return;
11560
11561 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11562 return;
11563
11564 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11565 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11566 return;
11567 }
11568 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11569 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11570 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11571
11572 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11573 ast_free(mwist);
11574 }
11575 }
11576
11577 static void start_poll_thread(void)
11578 {
11579 int errcode;
11580 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11581 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11582 AST_EVENT_IE_END);
11583
11584 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11585 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11586 AST_EVENT_IE_END);
11587
11588 if (mwi_sub_sub)
11589 ast_event_report_subs(mwi_sub_sub);
11590
11591 poll_thread_run = 1;
11592
11593 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11594 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11595 }
11596 }
11597
11598 static void stop_poll_thread(void)
11599 {
11600 poll_thread_run = 0;
11601
11602 if (mwi_sub_sub) {
11603 ast_event_unsubscribe(mwi_sub_sub);
11604 mwi_sub_sub = NULL;
11605 }
11606
11607 if (mwi_unsub_sub) {
11608 ast_event_unsubscribe(mwi_unsub_sub);
11609 mwi_unsub_sub = NULL;
11610 }
11611
11612 ast_mutex_lock(&poll_lock);
11613 ast_cond_signal(&poll_cond);
11614 ast_mutex_unlock(&poll_lock);
11615
11616 pthread_join(poll_thread, NULL);
11617
11618 poll_thread = AST_PTHREADT_NULL;
11619 }
11620
11621
11622 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11623 {
11624 struct ast_vm_user *vmu = NULL;
11625 const char *id = astman_get_header(m, "ActionID");
11626 char actionid[128] = "";
11627
11628 if (!ast_strlen_zero(id))
11629 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11630
11631 AST_LIST_LOCK(&users);
11632
11633 if (AST_LIST_EMPTY(&users)) {
11634 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11635 AST_LIST_UNLOCK(&users);
11636 return RESULT_SUCCESS;
11637 }
11638
11639 astman_send_ack(s, m, "Voicemail user list will follow");
11640
11641 AST_LIST_TRAVERSE(&users, vmu, list) {
11642 char dirname[256];
11643
11644 #ifdef IMAP_STORAGE
11645 int new, old;
11646 inboxcount(vmu->mailbox, &new, &old);
11647 #endif
11648
11649 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11650 astman_append(s,
11651 "%s"
11652 "Event: VoicemailUserEntry\r\n"
11653 "VMContext: %s\r\n"
11654 "VoiceMailbox: %s\r\n"
11655 "Fullname: %s\r\n"
11656 "Email: %s\r\n"
11657 "Pager: %s\r\n"
11658 "ServerEmail: %s\r\n"
11659 "MailCommand: %s\r\n"
11660 "Language: %s\r\n"
11661 "TimeZone: %s\r\n"
11662 "Callback: %s\r\n"
11663 "Dialout: %s\r\n"
11664 "UniqueID: %s\r\n"
11665 "ExitContext: %s\r\n"
11666 "SayDurationMinimum: %d\r\n"
11667 "SayEnvelope: %s\r\n"
11668 "SayCID: %s\r\n"
11669 "AttachMessage: %s\r\n"
11670 "AttachmentFormat: %s\r\n"
11671 "DeleteMessage: %s\r\n"
11672 "VolumeGain: %.2f\r\n"
11673 "CanReview: %s\r\n"
11674 "CallOperator: %s\r\n"
11675 "MaxMessageCount: %d\r\n"
11676 "MaxMessageLength: %d\r\n"
11677 "NewMessageCount: %d\r\n"
11678 #ifdef IMAP_STORAGE
11679 "OldMessageCount: %d\r\n"
11680 "IMAPUser: %s\r\n"
11681 #endif
11682 "\r\n",
11683 actionid,
11684 vmu->context,
11685 vmu->mailbox,
11686 vmu->fullname,
11687 vmu->email,
11688 vmu->pager,
11689 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
11690 mailcmd,
11691 vmu->language,
11692 vmu->zonetag,
11693 vmu->callback,
11694 vmu->dialout,
11695 vmu->uniqueid,
11696 vmu->exit,
11697 vmu->saydurationm,
11698 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11699 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11700 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11701 vmu->attachfmt,
11702 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11703 vmu->volgain,
11704 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11705 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11706 vmu->maxmsg,
11707 vmu->maxsecs,
11708 #ifdef IMAP_STORAGE
11709 new, old, vmu->imapuser
11710 #else
11711 count_messages(vmu, dirname)
11712 #endif
11713 );
11714 }
11715 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11716
11717 AST_LIST_UNLOCK(&users);
11718
11719 return RESULT_SUCCESS;
11720 }
11721
11722
11723 static void free_vm_users(void)
11724 {
11725 struct ast_vm_user *current;
11726 AST_LIST_LOCK(&users);
11727 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11728 ast_set_flag(current, VM_ALLOCED);
11729 free_user(current);
11730 }
11731 AST_LIST_UNLOCK(&users);
11732 }
11733
11734
11735 static void free_vm_zones(void)
11736 {
11737 struct vm_zone *zcur;
11738 AST_LIST_LOCK(&zones);
11739 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11740 free_zone(zcur);
11741 AST_LIST_UNLOCK(&zones);
11742 }
11743
11744 static const char *substitute_escapes(const char *value)
11745 {
11746 char *current;
11747
11748
11749 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11750
11751 ast_str_reset(str);
11752
11753
11754 for (current = (char *) value; *current; current++) {
11755 if (*current == '\\') {
11756 current++;
11757 if (!*current) {
11758 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11759 break;
11760 }
11761 switch (*current) {
11762 case '\\':
11763 ast_str_append(&str, 0, "\\");
11764 break;
11765 case 'r':
11766 ast_str_append(&str, 0, "\r");
11767 break;
11768 case 'n':
11769 #ifdef IMAP_STORAGE
11770 if (!str->used || str->str[str->used - 1] != '\r') {
11771 ast_str_append(&str, 0, "\r");
11772 }
11773 #endif
11774 ast_str_append(&str, 0, "\n");
11775 break;
11776 case 't':
11777 ast_str_append(&str, 0, "\t");
11778 break;
11779 default:
11780 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11781 break;
11782 }
11783 } else {
11784 ast_str_append(&str, 0, "%c", *current);
11785 }
11786 }
11787
11788 return ast_str_buffer(str);
11789 }
11790
11791 static int load_config(int reload)
11792 {
11793 struct ast_config *cfg, *ucfg;
11794 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11795 int res;
11796
11797 ast_unload_realtime("voicemail");
11798 ast_unload_realtime("voicemail_data");
11799
11800 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11801 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11802 return 0;
11803 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11804 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11805 ucfg = NULL;
11806 }
11807 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11808 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11809 ast_config_destroy(ucfg);
11810 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11811 return 0;
11812 }
11813 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11814 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11815 return 0;
11816 } else {
11817 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11818 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11819 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11820 ucfg = NULL;
11821 }
11822 }
11823
11824 res = actual_load_config(reload, cfg, ucfg);
11825
11826 ast_config_destroy(cfg);
11827 ast_config_destroy(ucfg);
11828
11829 return res;
11830 }
11831
11832 #ifdef TEST_FRAMEWORK
11833 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11834 {
11835 ast_unload_realtime("voicemail");
11836 ast_unload_realtime("voicemail_data");
11837 return actual_load_config(reload, cfg, ucfg);
11838 }
11839 #endif
11840
11841 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11842 {
11843 struct ast_vm_user *current;
11844 char *cat;
11845 struct ast_variable *var;
11846 const char *val;
11847 char *q, *stringp, *tmp;
11848 int x;
11849 unsigned int tmpadsi[4];
11850 char secretfn[PATH_MAX] = "";
11851
11852 #ifdef IMAP_STORAGE
11853 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11854 #endif
11855
11856 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11857 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11858 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11859 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11860 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11861
11862
11863 free_vm_users();
11864
11865
11866 free_vm_zones();
11867
11868 AST_LIST_LOCK(&users);
11869
11870 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11871 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11872
11873 if (cfg) {
11874
11875
11876 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11877 val = "default";
11878 ast_copy_string(userscontext, val, sizeof(userscontext));
11879
11880 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11881 val = "yes";
11882 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11883
11884 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11885 val = "no";
11886 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11887
11888 volgain = 0.0;
11889 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11890 sscanf(val, "%30lf", &volgain);
11891
11892 #ifdef ODBC_STORAGE
11893 strcpy(odbc_database, "asterisk");
11894 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11895 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11896 }
11897 strcpy(odbc_table, "voicemessages");
11898 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11899 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11900 }
11901 #endif
11902
11903 strcpy(mailcmd, SENDMAIL);
11904 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11905 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11906
11907 maxsilence = 0;
11908 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11909 maxsilence = atoi(val);
11910 if (maxsilence > 0)
11911 maxsilence *= 1000;
11912 }
11913
11914 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11915 maxmsg = MAXMSG;
11916 } else {
11917 maxmsg = atoi(val);
11918 if (maxmsg < 0) {
11919 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11920 maxmsg = MAXMSG;
11921 } else if (maxmsg > MAXMSGLIMIT) {
11922 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11923 maxmsg = MAXMSGLIMIT;
11924 }
11925 }
11926
11927 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11928 maxdeletedmsg = 0;
11929 } else {
11930 if (sscanf(val, "%30d", &x) == 1)
11931 maxdeletedmsg = x;
11932 else if (ast_true(val))
11933 maxdeletedmsg = MAXMSG;
11934 else
11935 maxdeletedmsg = 0;
11936
11937 if (maxdeletedmsg < 0) {
11938 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11939 maxdeletedmsg = MAXMSG;
11940 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11941 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11942 maxdeletedmsg = MAXMSGLIMIT;
11943 }
11944 }
11945
11946
11947 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11948 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11949 }
11950
11951
11952 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11953 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11954 }
11955
11956
11957 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11958 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11959 pwdchange = PWDCHANGE_EXTERNAL;
11960 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11961 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11962 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11963 }
11964
11965
11966 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11967 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11968 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11969 }
11970
11971 #ifdef IMAP_STORAGE
11972
11973 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11974 ast_copy_string(imapserver, val, sizeof(imapserver));
11975 } else {
11976 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11977 }
11978
11979 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11980 ast_copy_string(imapport, val, sizeof(imapport));
11981 } else {
11982 ast_copy_string(imapport, "143", sizeof(imapport));
11983 }
11984
11985 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11986 ast_copy_string(imapflags, val, sizeof(imapflags));
11987 }
11988
11989 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11990 ast_copy_string(authuser, val, sizeof(authuser));
11991 }
11992
11993 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11994 ast_copy_string(authpassword, val, sizeof(authpassword));
11995 }
11996
11997 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11998 if (ast_false(val))
11999 expungeonhangup = 0;
12000 else
12001 expungeonhangup = 1;
12002 } else {
12003 expungeonhangup = 1;
12004 }
12005
12006 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12007 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12008 } else {
12009 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12010 }
12011 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12012 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12013 }
12014 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12015 imapgreetings = ast_true(val);
12016 } else {
12017 imapgreetings = 0;
12018 }
12019 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12020 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12021 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12022
12023 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12024 } else {
12025 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12026 }
12027
12028
12029
12030
12031
12032 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12033 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12034 } else {
12035 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12036 }
12037
12038 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12039 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12040 } else {
12041 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12042 }
12043
12044 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12045 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12046 } else {
12047 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12048 }
12049
12050 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12051 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12052 } else {
12053 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12054 }
12055
12056
12057 imapversion++;
12058 #endif
12059
12060 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12061 ast_copy_string(externnotify, val, sizeof(externnotify));
12062 ast_debug(1, "found externnotify: %s\n", externnotify);
12063 } else {
12064 externnotify[0] = '\0';
12065 }
12066
12067
12068 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12069 ast_debug(1, "Enabled SMDI voicemail notification\n");
12070 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12071 smdi_iface = ast_smdi_interface_find(val);
12072 } else {
12073 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12074 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12075 }
12076 if (!smdi_iface) {
12077 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12078 }
12079 }
12080
12081
12082 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12083 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12084 silencethreshold = atoi(val);
12085
12086 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12087 val = ASTERISK_USERNAME;
12088 ast_copy_string(serveremail, val, sizeof(serveremail));
12089
12090 vmmaxsecs = 0;
12091 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12092 if (sscanf(val, "%30d", &x) == 1) {
12093 vmmaxsecs = x;
12094 } else {
12095 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12096 }
12097 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12098 static int maxmessage_deprecate = 0;
12099 if (maxmessage_deprecate == 0) {
12100 maxmessage_deprecate = 1;
12101 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12102 }
12103 if (sscanf(val, "%30d", &x) == 1) {
12104 vmmaxsecs = x;
12105 } else {
12106 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12107 }
12108 }
12109
12110 vmminsecs = 0;
12111 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12112 if (sscanf(val, "%30d", &x) == 1) {
12113 vmminsecs = x;
12114 if (maxsilence / 1000 >= vmminsecs) {
12115 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12116 }
12117 } else {
12118 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12119 }
12120 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12121 static int maxmessage_deprecate = 0;
12122 if (maxmessage_deprecate == 0) {
12123 maxmessage_deprecate = 1;
12124 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12125 }
12126 if (sscanf(val, "%30d", &x) == 1) {
12127 vmminsecs = x;
12128 if (maxsilence / 1000 >= vmminsecs) {
12129 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12130 }
12131 } else {
12132 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12133 }
12134 }
12135
12136 val = ast_variable_retrieve(cfg, "general", "format");
12137 if (!val) {
12138 val = "wav";
12139 } else {
12140 tmp = ast_strdupa(val);
12141 val = ast_format_str_reduce(tmp);
12142 if (!val) {
12143 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12144 val = "wav";
12145 }
12146 }
12147 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12148
12149 skipms = 3000;
12150 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12151 if (sscanf(val, "%30d", &x) == 1) {
12152 maxgreet = x;
12153 } else {
12154 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12155 }
12156 }
12157
12158 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12159 if (sscanf(val, "%30d", &x) == 1) {
12160 skipms = x;
12161 } else {
12162 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12163 }
12164 }
12165
12166 maxlogins = 3;
12167 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12168 if (sscanf(val, "%30d", &x) == 1) {
12169 maxlogins = x;
12170 } else {
12171 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12172 }
12173 }
12174
12175 minpassword = MINPASSWORD;
12176 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12177 if (sscanf(val, "%30d", &x) == 1) {
12178 minpassword = x;
12179 } else {
12180 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12181 }
12182 }
12183
12184
12185 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12186 val = "no";
12187 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12188
12189
12190 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12191 val = "no";
12192 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12193
12194 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12195 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12196 stringp = ast_strdupa(val);
12197 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12198 if (!ast_strlen_zero(stringp)) {
12199 q = strsep(&stringp, ",");
12200 while ((*q == ' ')||(*q == '\t'))
12201 q++;
12202 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12203 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12204 } else {
12205 cidinternalcontexts[x][0] = '\0';
12206 }
12207 }
12208 }
12209 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12210 ast_debug(1, "VM Review Option disabled globally\n");
12211 val = "no";
12212 }
12213 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12214
12215
12216 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12217 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12218 val = "no";
12219 } else {
12220 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12221 }
12222 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12223 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12224 ast_debug(1, "VM next message wrap disabled globally\n");
12225 val = "no";
12226 }
12227 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12228
12229 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12230 ast_debug(1, "VM Operator break disabled globally\n");
12231 val = "no";
12232 }
12233 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12234
12235 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12236 ast_debug(1, "VM CID Info before msg disabled globally\n");
12237 val = "no";
12238 }
12239 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12240
12241 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12242 ast_debug(1, "Send Voicemail msg disabled globally\n");
12243 val = "no";
12244 }
12245 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12246
12247 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12248 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12249 val = "yes";
12250 }
12251 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12252
12253 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12254 ast_debug(1, "Move Heard enabled globally\n");
12255 val = "yes";
12256 }
12257 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12258
12259 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12260 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12261 val = "no";
12262 }
12263 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12264
12265 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12266 ast_debug(1, "Duration info before msg enabled globally\n");
12267 val = "yes";
12268 }
12269 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12270
12271 saydurationminfo = 2;
12272 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12273 if (sscanf(val, "%30d", &x) == 1) {
12274 saydurationminfo = x;
12275 } else {
12276 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12277 }
12278 }
12279
12280 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12281 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12282 val = "no";
12283 }
12284 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12285
12286 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12287 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12288 ast_debug(1, "found dialout context: %s\n", dialcontext);
12289 } else {
12290 dialcontext[0] = '\0';
12291 }
12292
12293 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12294 ast_copy_string(callcontext, val, sizeof(callcontext));
12295 ast_debug(1, "found callback context: %s\n", callcontext);
12296 } else {
12297 callcontext[0] = '\0';
12298 }
12299
12300 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12301 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12302 ast_debug(1, "found operator context: %s\n", exitcontext);
12303 } else {
12304 exitcontext[0] = '\0';
12305 }
12306
12307
12308 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12309 ast_copy_string(vm_password, val, sizeof(vm_password));
12310 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12311 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12312 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12313 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12314 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12315 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12316 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12317 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12318 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12319 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12320 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12321 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12322 }
12323 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12324 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12325 }
12326
12327 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12328 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12329 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12330 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12331 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12332 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12333 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12334 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12335 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12336 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12337
12338 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12339 val = "no";
12340 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12341
12342 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12343 val = "voicemail.conf";
12344 }
12345 if (!(strcmp(val, "spooldir"))) {
12346 passwordlocation = OPT_PWLOC_SPOOLDIR;
12347 } else {
12348 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12349 }
12350
12351 poll_freq = DEFAULT_POLL_FREQ;
12352 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12353 if (sscanf(val, "%30u", &poll_freq) != 1) {
12354 poll_freq = DEFAULT_POLL_FREQ;
12355 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12356 }
12357 }
12358
12359 poll_mailboxes = 0;
12360 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12361 poll_mailboxes = ast_true(val);
12362
12363 memset(fromstring, 0, sizeof(fromstring));
12364 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12365 strcpy(charset, "ISO-8859-1");
12366 if (emailbody) {
12367 ast_free(emailbody);
12368 emailbody = NULL;
12369 }
12370 if (emailsubject) {
12371 ast_free(emailsubject);
12372 emailsubject = NULL;
12373 }
12374 if (pagerbody) {
12375 ast_free(pagerbody);
12376 pagerbody = NULL;
12377 }
12378 if (pagersubject) {
12379 ast_free(pagersubject);
12380 pagersubject = NULL;
12381 }
12382 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12383 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12384 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12385 ast_copy_string(fromstring, val, sizeof(fromstring));
12386 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12387 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12388 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12389 ast_copy_string(charset, val, sizeof(charset));
12390 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12391 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12392 for (x = 0; x < 4; x++) {
12393 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12394 }
12395 }
12396 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12397 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12398 for (x = 0; x < 4; x++) {
12399 memcpy(&adsisec[x], &tmpadsi[x], 1);
12400 }
12401 }
12402 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12403 if (atoi(val)) {
12404 adsiver = atoi(val);
12405 }
12406 }
12407 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12408 ast_copy_string(zonetag, val, sizeof(zonetag));
12409 }
12410 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12411 ast_copy_string(locale, val, sizeof(locale));
12412 }
12413 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12414 emailsubject = ast_strdup(substitute_escapes(val));
12415 }
12416 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12417 emailbody = ast_strdup(substitute_escapes(val));
12418 }
12419 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12420 pagersubject = ast_strdup(substitute_escapes(val));
12421 }
12422 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12423 pagerbody = ast_strdup(substitute_escapes(val));
12424 }
12425
12426
12427 if (ucfg) {
12428 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12429 if (!strcasecmp(cat, "general")) {
12430 continue;
12431 }
12432 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12433 continue;
12434 if ((current = find_or_create(userscontext, cat))) {
12435 populate_defaults(current);
12436 apply_options_full(current, ast_variable_browse(ucfg, cat));
12437 ast_copy_string(current->context, userscontext, sizeof(current->context));
12438 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12439 current->passwordlocation = OPT_PWLOC_USERSCONF;
12440 }
12441
12442 switch (current->passwordlocation) {
12443 case OPT_PWLOC_SPOOLDIR:
12444 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12445 read_password_from_file(secretfn, current->password, sizeof(current->password));
12446 }
12447 }
12448 }
12449 }
12450
12451
12452 cat = ast_category_browse(cfg, NULL);
12453 while (cat) {
12454 if (strcasecmp(cat, "general")) {
12455 var = ast_variable_browse(cfg, cat);
12456 if (strcasecmp(cat, "zonemessages")) {
12457
12458 while (var) {
12459 append_mailbox(cat, var->name, var->value);
12460 var = var->next;
12461 }
12462 } else {
12463
12464 while (var) {
12465 struct vm_zone *z;
12466 if ((z = ast_malloc(sizeof(*z)))) {
12467 char *msg_format, *tzone;
12468 msg_format = ast_strdupa(var->value);
12469 tzone = strsep(&msg_format, "|,");
12470 if (msg_format) {
12471 ast_copy_string(z->name, var->name, sizeof(z->name));
12472 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12473 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12474 AST_LIST_LOCK(&zones);
12475 AST_LIST_INSERT_HEAD(&zones, z, list);
12476 AST_LIST_UNLOCK(&zones);
12477 } else {
12478 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12479 ast_free(z);
12480 }
12481 } else {
12482 AST_LIST_UNLOCK(&users);
12483 return -1;
12484 }
12485 var = var->next;
12486 }
12487 }
12488 }
12489 cat = ast_category_browse(cfg, cat);
12490 }
12491
12492 AST_LIST_UNLOCK(&users);
12493
12494 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12495 start_poll_thread();
12496 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12497 stop_poll_thread();;
12498
12499 return 0;
12500 } else {
12501 AST_LIST_UNLOCK(&users);
12502 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12503 return 0;
12504 }
12505 }
12506
12507 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12508 {
12509 int res = -1;
12510 char dir[PATH_MAX];
12511 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12512 ast_debug(2, "About to try retrieving name file %s\n", dir);
12513 RETRIEVE(dir, -1, mailbox, context);
12514 if (ast_fileexists(dir, NULL, NULL)) {
12515 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12516 }
12517 DISPOSE(dir, -1);
12518 return res;
12519 }
12520
12521 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12522 struct ast_config *pwconf;
12523 struct ast_flags config_flags = { 0 };
12524
12525 pwconf = ast_config_load(secretfn, config_flags);
12526 if (valid_config(pwconf)) {
12527 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12528 if (val) {
12529 ast_copy_string(password, val, passwordlen);
12530 ast_config_destroy(pwconf);
12531 return;
12532 }
12533 ast_config_destroy(pwconf);
12534 }
12535 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12536 }
12537
12538 static int write_password_to_file(const char *secretfn, const char *password) {
12539 struct ast_config *conf;
12540 struct ast_category *cat;
12541 struct ast_variable *var;
12542 int res = -1;
12543
12544 if (!(conf = ast_config_new())) {
12545 ast_log(LOG_ERROR, "Error creating new config structure\n");
12546 return res;
12547 }
12548 if (!(cat = ast_category_new("general", "", 1))) {
12549 ast_log(LOG_ERROR, "Error creating new category structure\n");
12550 ast_config_destroy(conf);
12551 return res;
12552 }
12553 if (!(var = ast_variable_new("password", password, ""))) {
12554 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12555 ast_config_destroy(conf);
12556 ast_category_destroy(cat);
12557 return res;
12558 }
12559 ast_category_append(conf, cat);
12560 ast_variable_append(cat, var);
12561 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12562 res = 0;
12563 } else {
12564 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12565 }
12566
12567 ast_config_destroy(conf);
12568 return res;
12569 }
12570
12571 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12572 {
12573 char *context;
12574 char *args_copy;
12575 int res;
12576
12577 if (ast_strlen_zero(data)) {
12578 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12579 return -1;
12580 }
12581
12582 args_copy = ast_strdupa(data);
12583 if ((context = strchr(args_copy, '@'))) {
12584 *context++ = '\0';
12585 } else {
12586 context = "default";
12587 }
12588
12589 if ((res = sayname(chan, args_copy, context) < 0)) {
12590 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12591 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12592 if (!res) {
12593 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12594 }
12595 }
12596
12597 return res;
12598 }
12599
12600 #ifdef TEST_FRAMEWORK
12601 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12602 {
12603 return 0;
12604 }
12605
12606 static struct ast_frame *fake_read(struct ast_channel *ast)
12607 {
12608 return &ast_null_frame;
12609 }
12610
12611 AST_TEST_DEFINE(test_voicemail_vmsayname)
12612 {
12613 char dir[PATH_MAX];
12614 char dir2[PATH_MAX];
12615 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12616 static const char TEST_EXTENSION[] = "1234";
12617
12618 struct ast_channel *test_channel1 = NULL;
12619 int res = -1;
12620
12621 static const struct ast_channel_tech fake_tech = {
12622 .write = fake_write,
12623 .read = fake_read,
12624 };
12625
12626 switch (cmd) {
12627 case TEST_INIT:
12628 info->name = "vmsayname_exec";
12629 info->category = "/apps/app_voicemail/";
12630 info->summary = "Vmsayname unit test";
12631 info->description =
12632 "This tests passing various parameters to vmsayname";
12633 return AST_TEST_NOT_RUN;
12634 case TEST_EXECUTE:
12635 break;
12636 }
12637
12638 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12639 NULL, NULL, 0, 0, "TestChannel1"))) {
12640 goto exit_vmsayname_test;
12641 }
12642
12643
12644 test_channel1->nativeformats = AST_FORMAT_GSM;
12645 test_channel1->writeformat = AST_FORMAT_GSM;
12646 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12647 test_channel1->readformat = AST_FORMAT_GSM;
12648 test_channel1->rawreadformat = AST_FORMAT_GSM;
12649 test_channel1->tech = &fake_tech;
12650
12651 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12652 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12653 if (!(res = vmsayname_exec(test_channel1, dir))) {
12654 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12655 if (ast_fileexists(dir, NULL, NULL)) {
12656 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12657 res = -1;
12658 goto exit_vmsayname_test;
12659 } else {
12660
12661 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12662 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12663 goto exit_vmsayname_test;
12664 }
12665 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12666 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12667
12668 if ((res = symlink(dir, dir2))) {
12669 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12670 goto exit_vmsayname_test;
12671 }
12672 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12673 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12674 res = vmsayname_exec(test_channel1, dir);
12675
12676
12677 unlink(dir2);
12678 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12679 rmdir(dir2);
12680 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12681 rmdir(dir2);
12682 }
12683 }
12684
12685 exit_vmsayname_test:
12686
12687 if (test_channel1) {
12688 ast_hangup(test_channel1);
12689 }
12690
12691 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12692 }
12693
12694 AST_TEST_DEFINE(test_voicemail_msgcount)
12695 {
12696 int i, j, res = AST_TEST_PASS, syserr;
12697 struct ast_vm_user *vmu;
12698 struct ast_vm_user svm;
12699 struct vm_state vms;
12700 #ifdef IMAP_STORAGE
12701 struct ast_channel *chan = NULL;
12702 #endif
12703 struct {
12704 char dir[256];
12705 char file[256];
12706 char txtfile[256];
12707 } tmp[3];
12708 char syscmd[256];
12709 const char origweasels[] = "tt-weasels";
12710 const char testcontext[] = "test";
12711 const char testmailbox[] = "00000000";
12712 const char testspec[] = "00000000@test";
12713 FILE *txt;
12714 int new, old, urgent;
12715 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12716 const int folder2mbox[3] = { 1, 11, 0 };
12717 const int expected_results[3][12] = {
12718
12719 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12720 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12721 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12722 };
12723
12724 switch (cmd) {
12725 case TEST_INIT:
12726 info->name = "test_voicemail_msgcount";
12727 info->category = "/apps/app_voicemail/";
12728 info->summary = "Test Voicemail status checks";
12729 info->description =
12730 "Verify that message counts are correct when retrieved through the public API";
12731 return AST_TEST_NOT_RUN;
12732 case TEST_EXECUTE:
12733 break;
12734 }
12735
12736
12737 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12738 if ((syserr = ast_safe_system(syscmd))) {
12739 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12740 syserr > 0 ? strerror(syserr) : "unable to fork()");
12741 return AST_TEST_FAIL;
12742 }
12743
12744 #ifdef IMAP_STORAGE
12745 if (!(chan = ast_dummy_channel_alloc())) {
12746 ast_test_status_update(test, "Unable to create dummy channel\n");
12747 return AST_TEST_FAIL;
12748 }
12749 #endif
12750
12751 if (!(vmu = find_user(&svm, testcontext, testmailbox)) &&
12752 !(vmu = find_or_create(testcontext, testmailbox))) {
12753 ast_test_status_update(test, "Cannot create vmu structure\n");
12754 ast_unreplace_sigchld();
12755 #ifdef IMAP_STORAGE
12756 chan = ast_channel_unref(chan);
12757 #endif
12758 return AST_TEST_FAIL;
12759 }
12760
12761 populate_defaults(vmu);
12762 memset(&vms, 0, sizeof(vms));
12763
12764
12765 for (i = 0; i < 3; i++) {
12766 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12767 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12768 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12769
12770 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12771 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12772 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12773 if ((syserr = ast_safe_system(syscmd))) {
12774 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12775 syserr > 0 ? strerror(syserr) : "unable to fork()");
12776 ast_unreplace_sigchld();
12777 #ifdef IMAP_STORAGE
12778 chan = ast_channel_unref(chan);
12779 #endif
12780 return AST_TEST_FAIL;
12781 }
12782 }
12783
12784 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12785 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12786 fclose(txt);
12787 } else {
12788 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12789 res = AST_TEST_FAIL;
12790 break;
12791 }
12792 open_mailbox(&vms, vmu, folder2mbox[i]);
12793 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12794
12795
12796 for (j = 0; j < 3; j++) {
12797
12798 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12799 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12800 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12801 res = AST_TEST_FAIL;
12802 }
12803 }
12804
12805 new = old = urgent = 0;
12806 if (ast_app_inboxcount(testspec, &new, &old)) {
12807 ast_test_status_update(test, "inboxcount returned failure\n");
12808 res = AST_TEST_FAIL;
12809 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12810 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12811 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12812 res = AST_TEST_FAIL;
12813 }
12814
12815 new = old = urgent = 0;
12816 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12817 ast_test_status_update(test, "inboxcount2 returned failure\n");
12818 res = AST_TEST_FAIL;
12819 } else if (old != expected_results[i][6 + 0] ||
12820 urgent != expected_results[i][6 + 1] ||
12821 new != expected_results[i][6 + 2] ) {
12822 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12823 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12824 res = AST_TEST_FAIL;
12825 }
12826
12827 new = old = urgent = 0;
12828 for (j = 0; j < 3; j++) {
12829 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12830 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12831 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12832 res = AST_TEST_FAIL;
12833 }
12834 }
12835 }
12836
12837 for (i = 0; i < 3; i++) {
12838
12839
12840
12841 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12842 DISPOSE(tmp[i].dir, 0);
12843 }
12844
12845 if (vms.deleted) {
12846 ast_free(vms.deleted);
12847 }
12848 if (vms.heard) {
12849 ast_free(vms.heard);
12850 }
12851
12852 #ifdef IMAP_STORAGE
12853 chan = ast_channel_unref(chan);
12854 #endif
12855
12856
12857 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12858 if ((syserr = ast_safe_system(syscmd))) {
12859 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12860 syserr > 0 ? strerror(syserr) : "unable to fork()");
12861 }
12862
12863 return res;
12864 }
12865
12866 AST_TEST_DEFINE(test_voicemail_notify_endl)
12867 {
12868 int res = AST_TEST_PASS;
12869 char testcontext[] = "test";
12870 char testmailbox[] = "00000000";
12871 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12872 char attach[256], attach2[256];
12873 char buf[256] = "";
12874 struct ast_channel *chan = NULL;
12875 struct ast_vm_user *vmu, vmus = {
12876 .flags = 0,
12877 };
12878 FILE *file;
12879 struct {
12880 char *name;
12881 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12882 void *location;
12883 union {
12884 int intval;
12885 char *strval;
12886 } u;
12887 } test_items[] = {
12888 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12889 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12890 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12891 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12892 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12893 { "attach2", STRPTR, attach2, .u.strval = "" },
12894 { "attach", STRPTR, attach, .u.strval = "" },
12895 };
12896 int which;
12897
12898 switch (cmd) {
12899 case TEST_INIT:
12900 info->name = "test_voicemail_notify_endl";
12901 info->category = "/apps/app_voicemail/";
12902 info->summary = "Test Voicemail notification end-of-line";
12903 info->description =
12904 "Verify that notification emails use a consistent end-of-line character";
12905 return AST_TEST_NOT_RUN;
12906 case TEST_EXECUTE:
12907 break;
12908 }
12909
12910 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12911 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12912
12913 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12914 !(vmu = find_or_create(testcontext, testmailbox))) {
12915 ast_test_status_update(test, "Cannot create vmu structure\n");
12916 return AST_TEST_NOT_RUN;
12917 }
12918
12919 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12920 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12921 return AST_TEST_NOT_RUN;
12922 }
12923
12924 populate_defaults(vmu);
12925 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12926 #ifdef IMAP_STORAGE
12927
12928 #endif
12929
12930 file = tmpfile();
12931 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12932
12933 rewind(file);
12934 if (ftruncate(fileno(file), 0)) {
12935 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12936 res = AST_TEST_FAIL;
12937 break;
12938 }
12939
12940
12941 if (test_items[which].type == INT) {
12942 *((int *) test_items[which].location) = test_items[which].u.intval;
12943 } else if (test_items[which].type == FLAGVAL) {
12944 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12945 ast_clear_flag(vmu, test_items[which].u.intval);
12946 } else {
12947 ast_set_flag(vmu, test_items[which].u.intval);
12948 }
12949 } else if (test_items[which].type == STATIC) {
12950 strcpy(test_items[which].location, test_items[which].u.strval);
12951 } else if (test_items[which].type == STRPTR) {
12952 test_items[which].location = test_items[which].u.strval;
12953 }
12954
12955 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12956 rewind(file);
12957 while (fgets(buf, sizeof(buf), file)) {
12958 if (
12959 #ifdef IMAP_STORAGE
12960 buf[strlen(buf) - 2] != '\r'
12961 #else
12962 buf[strlen(buf) - 2] == '\r'
12963 #endif
12964 || buf[strlen(buf) - 1] != '\n') {
12965 res = AST_TEST_FAIL;
12966 }
12967 }
12968 }
12969 fclose(file);
12970 return res;
12971 }
12972
12973 AST_TEST_DEFINE(test_voicemail_load_config)
12974 {
12975 int res = AST_TEST_PASS;
12976 struct ast_vm_user *vmu;
12977 struct ast_config *cfg;
12978 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
12979 int fd;
12980 FILE *file;
12981 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
12982
12983 switch (cmd) {
12984 case TEST_INIT:
12985 info->name = "test_voicemail_load_config";
12986 info->category = "/apps/app_voicemail/";
12987 info->summary = "Test loading Voicemail config";
12988 info->description =
12989 "Verify that configuration is loaded consistently. "
12990 "This is to test regressions of ASTERISK-18838 where it was noticed that "
12991 "some options were loaded after the mailboxes were instantiated, causing "
12992 "those options not to be set correctly.";
12993 return AST_TEST_NOT_RUN;
12994 case TEST_EXECUTE:
12995 break;
12996 }
12997
12998
12999 if ((fd = mkstemp(config_filename)) < 0) {
13000 return AST_TEST_FAIL;
13001 }
13002 if (!(file = fdopen(fd, "w"))) {
13003 close(fd);
13004 unlink(config_filename);
13005 return AST_TEST_FAIL;
13006 }
13007 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13008 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13009 fputs("00000002 => 9999,Mrs. Test\n", file);
13010 fclose(file);
13011
13012 if (!(cfg = ast_config_load(config_filename, config_flags)) || !valid_config(cfg)) {
13013 res = AST_TEST_FAIL;
13014 goto cleanup;
13015 }
13016
13017 load_config_from_memory(1, cfg, NULL);
13018 ast_config_destroy(cfg);
13019
13020 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13021 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13022 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13023
13024 AST_LIST_LOCK(&users);
13025 AST_LIST_TRAVERSE(&users, vmu, list) {
13026 if (!strcmp(vmu->mailbox, "00000001")) {
13027 if (0);
13028 CHECK(vmu, callback, "othercontext")
13029 CHECK(vmu, locale, "nl_NL.UTF-8")
13030 CHECK(vmu, zonetag, "central")
13031 } else if (!strcmp(vmu->mailbox, "00000002")) {
13032 if (0);
13033 CHECK(vmu, callback, "somecontext")
13034 CHECK(vmu, locale, "de_DE.UTF-8")
13035 CHECK(vmu, zonetag, "european")
13036 }
13037 }
13038 AST_LIST_UNLOCK(&users);
13039
13040 #undef CHECK
13041
13042
13043 load_config(1);
13044
13045 cleanup:
13046 unlink(config_filename);
13047 return res;
13048 }
13049
13050 #endif
13051
13052 static int reload(void)
13053 {
13054 return load_config(1);
13055 }
13056
13057 static int unload_module(void)
13058 {
13059 int res;
13060
13061 res = ast_unregister_application(app);
13062 res |= ast_unregister_application(app2);
13063 res |= ast_unregister_application(app3);
13064 res |= ast_unregister_application(app4);
13065 res |= ast_unregister_application(sayname_app);
13066 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13067 res |= ast_manager_unregister("VoicemailUsersList");
13068 res |= ast_data_unregister(NULL);
13069 #ifdef TEST_FRAMEWORK
13070 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13071 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13072 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13073 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13074 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13075 #endif
13076 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13077 ast_uninstall_vm_functions();
13078 ao2_ref(inprocess_container, -1);
13079
13080 if (poll_thread != AST_PTHREADT_NULL)
13081 stop_poll_thread();
13082
13083 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13084 ast_unload_realtime("voicemail");
13085 ast_unload_realtime("voicemail_data");
13086
13087 free_vm_users();
13088 free_vm_zones();
13089 return res;
13090 }
13091
13092 static int load_module(void)
13093 {
13094 int res;
13095 my_umask = umask(0);
13096 umask(my_umask);
13097
13098 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13099 return AST_MODULE_LOAD_DECLINE;
13100 }
13101
13102
13103 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13104
13105 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13106 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13107 }
13108
13109 if ((res = load_config(0)))
13110 return res;
13111
13112 res = ast_register_application_xml(app, vm_exec);
13113 res |= ast_register_application_xml(app2, vm_execmain);
13114 res |= ast_register_application_xml(app3, vm_box_exists);
13115 res |= ast_register_application_xml(app4, vmauthenticate);
13116 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13117 res |= ast_custom_function_register(&mailbox_exists_acf);
13118 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13119 #ifdef TEST_FRAMEWORK
13120 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13121 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13122 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13123 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13124 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13125 #endif
13126
13127 if (res)
13128 return res;
13129
13130 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13131 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13132
13133 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13134 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13135 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13136
13137 return res;
13138 }
13139
13140 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13141 {
13142 int cmd = 0;
13143 char destination[80] = "";
13144 int retries = 0;
13145
13146 if (!num) {
13147 ast_verb(3, "Destination number will be entered manually\n");
13148 while (retries < 3 && cmd != 't') {
13149 destination[1] = '\0';
13150 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13151 if (!cmd)
13152 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13153 if (!cmd)
13154 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13155 if (!cmd) {
13156 cmd = ast_waitfordigit(chan, 6000);
13157 if (cmd)
13158 destination[0] = cmd;
13159 }
13160 if (!cmd) {
13161 retries++;
13162 } else {
13163
13164 if (cmd < 0)
13165 return 0;
13166 if (cmd == '*') {
13167 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13168 return 0;
13169 }
13170 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13171 retries++;
13172 else
13173 cmd = 't';
13174 }
13175 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13176 }
13177 if (retries >= 3) {
13178 return 0;
13179 }
13180
13181 } else {
13182 if (option_verbose > 2)
13183 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13184 ast_copy_string(destination, num, sizeof(destination));
13185 }
13186
13187 if (!ast_strlen_zero(destination)) {
13188 if (destination[strlen(destination) -1 ] == '*')
13189 return 0;
13190 if (option_verbose > 2)
13191 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13192 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13193 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13194 chan->priority = 0;
13195 return 9;
13196 }
13197 return 0;
13198 }
13199
13200
13201
13202
13203
13204
13205
13206
13207
13208
13209
13210
13211
13212
13213 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)
13214 {
13215 int res = 0;
13216 char filename[PATH_MAX];
13217 struct ast_config *msg_cfg = NULL;
13218 const char *origtime, *context;
13219 char *name, *num;
13220 int retries = 0;
13221 char *cid;
13222 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13223
13224 vms->starting = 0;
13225
13226 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13227
13228
13229 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13230 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13231 msg_cfg = ast_config_load(filename, config_flags);
13232 DISPOSE(vms->curdir, vms->curmsg);
13233 if (!valid_config(msg_cfg)) {
13234 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13235 return 0;
13236 }
13237
13238 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13239 ast_config_destroy(msg_cfg);
13240 return 0;
13241 }
13242
13243 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13244
13245 context = ast_variable_retrieve(msg_cfg, "message", "context");
13246 if (!strncasecmp("macro", context, 5))
13247 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13248 switch (option) {
13249 case 3:
13250 if (!res)
13251 res = play_message_datetime(chan, vmu, origtime, filename);
13252 if (!res)
13253 res = play_message_callerid(chan, vms, cid, context, 0);
13254
13255 res = 't';
13256 break;
13257
13258 case 2:
13259
13260 if (ast_strlen_zero(cid))
13261 break;
13262
13263 ast_callerid_parse(cid, &name, &num);
13264 while ((res > -1) && (res != 't')) {
13265 switch (res) {
13266 case '1':
13267 if (num) {
13268
13269 res = dialout(chan, vmu, num, vmu->callback);
13270 if (res) {
13271 ast_config_destroy(msg_cfg);
13272 return 9;
13273 }
13274 } else {
13275 res = '2';
13276 }
13277 break;
13278
13279 case '2':
13280
13281 if (!ast_strlen_zero(vmu->dialout)) {
13282 res = dialout(chan, vmu, NULL, vmu->dialout);
13283 if (res) {
13284 ast_config_destroy(msg_cfg);
13285 return 9;
13286 }
13287 } else {
13288 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13289 res = ast_play_and_wait(chan, "vm-sorry");
13290 }
13291 ast_config_destroy(msg_cfg);
13292 return res;
13293 case '*':
13294 res = 't';
13295 break;
13296 case '3':
13297 case '4':
13298 case '5':
13299 case '6':
13300 case '7':
13301 case '8':
13302 case '9':
13303 case '0':
13304
13305 res = ast_play_and_wait(chan, "vm-sorry");
13306 retries++;
13307 break;
13308 default:
13309 if (num) {
13310 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13311 res = ast_play_and_wait(chan, "vm-num-i-have");
13312 if (!res)
13313 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13314 if (!res)
13315 res = ast_play_and_wait(chan, "vm-tocallnum");
13316
13317 if (!ast_strlen_zero(vmu->dialout)) {
13318 if (!res)
13319 res = ast_play_and_wait(chan, "vm-calldiffnum");
13320 }
13321 } else {
13322 res = ast_play_and_wait(chan, "vm-nonumber");
13323 if (!ast_strlen_zero(vmu->dialout)) {
13324 if (!res)
13325 res = ast_play_and_wait(chan, "vm-toenternumber");
13326 }
13327 }
13328 if (!res) {
13329 res = ast_play_and_wait(chan, "vm-star-cancel");
13330 }
13331 if (!res) {
13332 res = ast_waitfordigit(chan, 6000);
13333 }
13334 if (!res) {
13335 retries++;
13336 if (retries > 3) {
13337 res = 't';
13338 }
13339 }
13340 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13341 break;
13342
13343 }
13344 if (res == 't')
13345 res = 0;
13346 else if (res == '*')
13347 res = -1;
13348 }
13349 break;
13350
13351 case 1:
13352
13353 if (ast_strlen_zero(cid))
13354 break;
13355
13356 ast_callerid_parse(cid, &name, &num);
13357 if (!num) {
13358 ast_verb(3, "No CID number available, no reply sent\n");
13359 if (!res)
13360 res = ast_play_and_wait(chan, "vm-nonumber");
13361 ast_config_destroy(msg_cfg);
13362 return res;
13363 } else {
13364 struct ast_vm_user vmu2;
13365 if (find_user(&vmu2, vmu->context, num)) {
13366 struct leave_vm_options leave_options;
13367 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13368 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13369
13370 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13371
13372 memset(&leave_options, 0, sizeof(leave_options));
13373 leave_options.record_gain = record_gain;
13374 res = leave_voicemail(chan, mailbox, &leave_options);
13375 if (!res)
13376 res = 't';
13377 ast_config_destroy(msg_cfg);
13378 return res;
13379 } else {
13380
13381 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13382 ast_play_and_wait(chan, "vm-nobox");
13383 res = 't';
13384 ast_config_destroy(msg_cfg);
13385 return res;
13386 }
13387 }
13388 res = 0;
13389
13390 break;
13391 }
13392
13393 ast_config_destroy(msg_cfg);
13394
13395 #ifndef IMAP_STORAGE
13396 if (!res) {
13397 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13398 vms->heard[msg] = 1;
13399 res = wait_file(chan, vms, vms->fn);
13400 }
13401 #endif
13402 return res;
13403 }
13404
13405 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13406 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13407 signed char record_gain, struct vm_state *vms, char *flag)
13408 {
13409
13410 int res = 0;
13411 int cmd = 0;
13412 int max_attempts = 3;
13413 int attempts = 0;
13414 int recorded = 0;
13415 int msg_exists = 0;
13416 signed char zero_gain = 0;
13417 char tempfile[PATH_MAX];
13418 char *acceptdtmf = "#";
13419 char *canceldtmf = "";
13420 int canceleddtmf = 0;
13421
13422
13423
13424
13425 if (duration == NULL) {
13426 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13427 return -1;
13428 }
13429
13430 if (!outsidecaller)
13431 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13432 else
13433 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13434
13435 cmd = '3';
13436
13437 while ((cmd >= 0) && (cmd != 't')) {
13438 switch (cmd) {
13439 case '1':
13440 if (!msg_exists) {
13441
13442 cmd = '3';
13443 break;
13444 } else {
13445
13446 ast_verb(3, "Saving message as is\n");
13447 if (!outsidecaller)
13448 ast_filerename(tempfile, recordfile, NULL);
13449 ast_stream_and_wait(chan, "vm-msgsaved", "");
13450 if (!outsidecaller) {
13451
13452 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13453 DISPOSE(recordfile, -1);
13454 }
13455 cmd = 't';
13456 return res;
13457 }
13458 case '2':
13459
13460 ast_verb(3, "Reviewing the message\n");
13461 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13462 break;
13463 case '3':
13464 msg_exists = 0;
13465
13466 if (recorded == 1)
13467 ast_verb(3, "Re-recording the message\n");
13468 else
13469 ast_verb(3, "Recording the message\n");
13470
13471 if (recorded && outsidecaller) {
13472 cmd = ast_play_and_wait(chan, INTRO);
13473 cmd = ast_play_and_wait(chan, "beep");
13474 }
13475 recorded = 1;
13476
13477 if (record_gain)
13478 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13479 if (ast_test_flag(vmu, VM_OPERATOR))
13480 canceldtmf = "0";
13481 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13482 if (strchr(canceldtmf, cmd)) {
13483
13484 canceleddtmf = 1;
13485 }
13486 if (record_gain)
13487 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13488 if (cmd == -1) {
13489
13490 if (!outsidecaller) {
13491
13492 ast_filedelete(tempfile, NULL);
13493 }
13494 return cmd;
13495 }
13496 if (cmd == '0') {
13497 break;
13498 } else if (cmd == '*') {
13499 break;
13500 #if 0
13501 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13502
13503 ast_verb(3, "Message too short\n");
13504 cmd = ast_play_and_wait(chan, "vm-tooshort");
13505 cmd = ast_filedelete(tempfile, NULL);
13506 break;
13507 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13508
13509 ast_verb(3, "Nothing recorded\n");
13510 cmd = ast_filedelete(tempfile, NULL);
13511 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13512 if (!cmd)
13513 cmd = ast_play_and_wait(chan, "vm-speakup");
13514 break;
13515 #endif
13516 } else {
13517
13518 msg_exists = 1;
13519 cmd = 0;
13520 }
13521 break;
13522 case '4':
13523 if (outsidecaller) {
13524
13525 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13526 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13527 res = ast_play_and_wait(chan, "vm-marked-urgent");
13528 strcpy(flag, "Urgent");
13529 } else if (flag) {
13530 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13531 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
13532 strcpy(flag, "");
13533 } else {
13534 ast_play_and_wait(chan, "vm-sorry");
13535 }
13536 cmd = 0;
13537 } else {
13538 cmd = ast_play_and_wait(chan, "vm-sorry");
13539 }
13540 break;
13541 case '5':
13542 case '6':
13543 case '7':
13544 case '8':
13545 case '9':
13546 case '*':
13547 case '#':
13548 cmd = ast_play_and_wait(chan, "vm-sorry");
13549 break;
13550 #if 0
13551
13552
13553 case '*':
13554
13555 cmd = ast_play_and_wait(chan, "vm-deleted");
13556 cmd = ast_filedelete(tempfile, NULL);
13557 if (outsidecaller) {
13558 res = vm_exec(chan, NULL);
13559 return res;
13560 }
13561 else
13562 return 1;
13563 #endif
13564 case '0':
13565 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13566 cmd = ast_play_and_wait(chan, "vm-sorry");
13567 break;
13568 }
13569 if (msg_exists || recorded) {
13570 cmd = ast_play_and_wait(chan, "vm-saveoper");
13571 if (!cmd)
13572 cmd = ast_waitfordigit(chan, 3000);
13573 if (cmd == '1') {
13574 ast_filerename(tempfile, recordfile, NULL);
13575 ast_play_and_wait(chan, "vm-msgsaved");
13576 cmd = '0';
13577 } else if (cmd == '4') {
13578 if (flag) {
13579 ast_play_and_wait(chan, "vm-marked-urgent");
13580 strcpy(flag, "Urgent");
13581 }
13582 ast_play_and_wait(chan, "vm-msgsaved");
13583 cmd = '0';
13584 } else {
13585 ast_play_and_wait(chan, "vm-deleted");
13586 DELETE(tempfile, -1, tempfile, vmu);
13587 cmd = '0';
13588 }
13589 }
13590 return cmd;
13591 default:
13592
13593
13594
13595 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13596 return cmd;
13597 if (msg_exists) {
13598 cmd = ast_play_and_wait(chan, "vm-review");
13599 if (!cmd && outsidecaller) {
13600 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13601 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13602 } else if (flag) {
13603 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13604 }
13605 }
13606 } else {
13607 cmd = ast_play_and_wait(chan, "vm-torerecord");
13608 if (!cmd)
13609 cmd = ast_waitfordigit(chan, 600);
13610 }
13611
13612 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13613 cmd = ast_play_and_wait(chan, "vm-reachoper");
13614 if (!cmd)
13615 cmd = ast_waitfordigit(chan, 600);
13616 }
13617 #if 0
13618 if (!cmd)
13619 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13620 #endif
13621 if (!cmd)
13622 cmd = ast_waitfordigit(chan, 6000);
13623 if (!cmd) {
13624 attempts++;
13625 }
13626 if (attempts > max_attempts) {
13627 cmd = 't';
13628 }
13629 }
13630 }
13631 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13632
13633 ast_filedelete(tempfile, NULL);
13634 }
13635
13636 if (cmd != 't' && outsidecaller)
13637 ast_play_and_wait(chan, "vm-goodbye");
13638
13639 return cmd;
13640 }
13641
13642
13643
13644
13645
13646 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13647 .load = load_module,
13648 .unload = unload_module,
13649 .reload = reload,
13650 .nonoptreq = "res_adsi,res_smdi",
13651 );